Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
436 changes: 422 additions & 14 deletions frontend/app/globals.css

Large diffs are not rendered by default.

25 changes: 9 additions & 16 deletions frontend/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import { Inter } from "next/font/google";
import "./globals.css";
import { Metadata } from "next";
import { Toaster } from "sonner";

const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
});

const geistMono = Geist_Mono({
variable: "--font-geist-mono",
subsets: ["latin"],
});
const inter = Inter({ subsets: ["latin"] });

export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
title: "UptimeGuard - Website Monitoring",
description:
"Simple, reliable uptime monitoring from multiple global regions",
};

export default function RootLayout({
Expand All @@ -24,10 +18,9 @@ export default function RootLayout({
}>) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<body className={inter.className}>
{children}
<Toaster />
</body>
</html>
);
Expand Down
108 changes: 11 additions & 97 deletions frontend/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,103 +1,17 @@
import Image from "next/image";
import { Features } from "@/components/Features";
import { Footer } from "@/components/Footer";
import { Header } from "@/components/Header";
import { Hero } from "@/components/Hero";
import { StatusSection } from "@/components/StatusSection";

export default function Home() {
return (
<div className="grid grid-rows-[20px_1fr_20px] items-center justify-items-center min-h-screen p-8 pb-20 gap-16 sm:p-20 font-[family-name:var(--font-geist-sans)]">
<main className="flex flex-col gap-[32px] row-start-2 items-center sm:items-start">
<Image
className="dark:invert"
src="/next.svg"
alt="Next.js logo"
width={180}
height={38}
priority
/>
<ol className="list-inside list-decimal text-sm/6 text-center sm:text-left font-[family-name:var(--font-geist-mono)]">
<li className="mb-2 tracking-[-.01em]">
Get started by editing{" "}
<code className="bg-black/[.05] dark:bg-white/[.06] px-1 py-0.5 rounded font-[family-name:var(--font-geist-mono)] font-semibold">
app/page.tsx
</code>
.
</li>
<li className="tracking-[-.01em]">
Save and see your changes instantly.
</li>
</ol>

<div className="flex gap-4 items-center flex-col sm:flex-row">
<a
className="rounded-full border border-solid border-transparent transition-colors flex items-center justify-center bg-foreground text-background gap-2 hover:bg-[#383838] dark:hover:bg-[#ccc] font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 sm:w-auto"
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
className="dark:invert"
src="/vercel.svg"
alt="Vercel logomark"
width={20}
height={20}
/>
Deploy now
</a>
<a
className="rounded-full border border-solid border-black/[.08] dark:border-white/[.145] transition-colors flex items-center justify-center hover:bg-[#f2f2f2] dark:hover:bg-[#1a1a1a] hover:border-transparent font-medium text-sm sm:text-base h-10 sm:h-12 px-4 sm:px-5 w-full sm:w-auto md:w-[158px]"
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
Read our docs
</a>
</div>
</main>
<footer className="row-start-3 flex gap-[24px] flex-wrap items-center justify-center">
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/file.svg"
alt="File icon"
width={16}
height={16}
/>
Learn
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/window.svg"
alt="Window icon"
width={16}
height={16}
/>
Examples
</a>
<a
className="flex items-center gap-2 hover:underline hover:underline-offset-4"
href="https://nextjs.org?utm_source=create-next-app&utm_medium=appdir-template-tw&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
<Image
aria-hidden
src="/globe.svg"
alt="Globe icon"
width={16}
height={16}
/>
Go to nextjs.org →
</a>
</footer>
<div className="min-h-screen bg-background">
<Header />
<Hero />
<StatusSection />
<Features />
<Footer />
</div>
);
}
21 changes: 21 additions & 0 deletions frontend/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": true,
"tsx": true,
"tailwind": {
"config": "",
"css": "app/globals.css",
"baseColor": "neutral",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
},
"iconLibrary": "lucide"
}
89 changes: 89 additions & 0 deletions frontend/components/Features.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
"use client";

import { motion } from "motion/react";
import { Globe, Activity } from "lucide-react";

export const Features = () => {
const features = [
{
icon: Globe,
title: "Global Monitoring",
description:
"Monitor from multiple regions worldwide to ensure reliable uptime detection.",
},
{
icon: Activity,
title: "Instant Alerts",
description:
"Get notified immediately when your website goes down or comes back online.",
},
];

const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: {
staggerChildren: 0.2,
},
},
};

const itemVariants = {
hidden: { opacity: 0, y: 30 },
visible: {
opacity: 1,
y: 0,
transition: { duration: 0.6 },
},
};

return (
<section id="features" className="py-32 px-8">
<div className="container mx-auto max-w-6xl">
<motion.div
initial={{ opacity: 0, y: 30 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
transition={{ duration: 0.8 }}
className="text-center mb-20"
>
<h2 className="text-4xl md:text-5xl font-bold mb-6">
Simple monitoring
</h2>
<p className="text-xl text-muted-foreground max-w-2xl mx-auto">
Everything you need to keep your websites running smoothly.
</p>
</motion.div>

<motion.div
variants={containerVariants}
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
className="grid grid-cols-1 md:grid-cols-2 gap-16 max-w-4xl mx-auto"
>
{features.map((feature, index) => (
<motion.div
key={index}
variants={itemVariants}
className="text-center group"
>
<motion.div
className="w-16 h-16 mx-auto mb-6 rounded-2xl bg-gradient-card border border-border/50 flex items-center justify-center group-hover:bg-gradient-primary group-hover:text-primary-foreground transition-all duration-300 shadow-subtle group-hover:shadow-glow"
whileHover={{ scale: 1.05 }}
transition={{ duration: 0.2 }}
>
<feature.icon className="w-8 h-8" />
</motion.div>
<h3 className="text-2xl font-semibold mb-4">{feature.title}</h3>
<p className="text-lg text-muted-foreground leading-relaxed">
{feature.description}
</p>
</motion.div>
))}
</motion.div>
</div>
</section>
);
};
53 changes: 53 additions & 0 deletions frontend/components/Footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
export const Footer = () => {
return (
<footer className="border-t border-border bg-background">
<div className="container mx-auto px-8 py-16">
<div className="flex flex-col md:flex-row justify-between items-start md:items-center space-y-8 md:space-y-0">
<div>
<span className="font-semibold text-xl">UptimeGuard</span>
<p className="text-muted-foreground mt-2 max-w-md">
Simple, reliable website monitoring from multiple global regions.
</p>
</div>

<div className="flex flex-col sm:flex-row space-y-4 sm:space-y-0 sm:space-x-12">
<div className="space-y-2">
<a
href="#"
className="text-muted-foreground hover:text-foreground transition-colors block"
>
Privacy Policy
</a>
<a
href="#"
className="text-muted-foreground hover:text-foreground transition-colors block"
>
Terms of Service
</a>
</div>
<div className="space-y-2">
<a
href="#"
className="text-muted-foreground hover:text-foreground transition-colors block"
>
Support
</a>
<a
href="#"
className="text-muted-foreground hover:text-foreground transition-colors block"
>
Contact
</a>
</div>
</div>
</div>

<div className="border-t border-border mt-16 pt-8">
<p className="text-sm text-muted-foreground text-center">
© 2024 UptimeGuard. All rights reserved.
</p>
</div>
</div>
</footer>
);
};
62 changes: 62 additions & 0 deletions frontend/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
"use client";

import { useState } from "react";
import { motion } from "framer-motion";

import { AuthModal } from "@/components/auth/AuthModal";
import { Button } from "./ui/button";

export const Header = () => {
const [showAuthModal, setShowAuthModal] = useState(false);

return (
<>
<motion.header
initial={{ y: -100 }}
animate={{ y: 0 }}
transition={{ duration: 0.6, ease: "easeOut" }}
className="sticky top-0 z-50 w-full border-b border-border/50 bg-gradient-secondary/90 backdrop-blur-xl shadow-subtle"
>
<div className="container mx-auto flex h-20 items-center justify-between px-8">
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.2, duration: 0.5 }}
className="flex items-center"
>
<span className="font-semibold text-2xl tracking-tight">
UptimeGuard
</span>
</motion.div>

<nav className="hidden md:flex items-center space-x-12">
<motion.a
href="#features"
className="text-muted-foreground hover:text-foreground transition-colors duration-200 font-medium"
whileHover={{ y: -2 }}
transition={{ duration: 0.2 }}
>
Features
</motion.a>
</nav>

<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.4, duration: 0.5 }}
>
<Button
variant="ghost"
onClick={() => setShowAuthModal(true)}
className="font-medium hover:bg-secondary/50"
>
Sign In
</Button>
</motion.div>
</div>
</motion.header>

<AuthModal open={showAuthModal} onOpenChange={setShowAuthModal} />
</>
);
};
Loading