diff --git a/app/globals.css b/app/globals.css index 2d06d23..e9bbd1e 100644 --- a/app/globals.css +++ b/app/globals.css @@ -69,4 +69,15 @@ body { body { @apply bg-background text-foreground; } +} + +.mask-gradient { + mask-image: linear-gradient(to bottom, transparent, black 15%, black 85%, transparent); + -webkit-mask-image: linear-gradient(to bottom, transparent, black 15%, black 85%, transparent); +} + +.bg-grid-white { + background-size: 40px 40px; + background-image: linear-gradient(to right, rgba(255, 255, 255, 0.05) 1px, transparent 1px), + linear-gradient(to bottom, rgba(255, 255, 255, 0.05) 1px, transparent 1px); } \ No newline at end of file diff --git a/app/page.tsx b/app/page.tsx index 4beade9..e358afa 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,12 +1,13 @@ "use client" -import {QRCodeSVG} from 'qrcode.react'; +import React, { useState, useRef, useEffect } from 'react'; +import { motion, MotionProps } from "motion/react"; +import { QRCodeSVG } from 'qrcode.react'; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; -import { Input } from "@/components/ui/input" -import { Button } from "@/components/ui/button" +import { Input } from "@/components/ui/input"; +import { Button } from "@/components/ui/button"; import { useTheme } from "next-themes"; -import { ArrowDown, Github } from "lucide-react"; -import { useState } from "react"; +import { ArrowDown, Github, Sparkles, Rocket, Shield, ChartBar, Coffee, MousePointer2, Twitter, ExternalLink, Mail, Heart, Code, MessageCircle, } from "lucide-react"; import { CopyButton } from "@/components/copy-button"; import { AlertDialog, @@ -18,22 +19,73 @@ import { AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, -} from "@/components/ui/alert-dialog" -import { useRef } from "react"; +} from "@/components/ui/alert-dialog"; import { redirect } from 'next/navigation'; +import { Separator } from "@/components/ui/separator"; import Link from 'next/link'; +const FloatingCursor = () => { + const [position, setPosition] = useState({ x: 0, y: 0 }); + + useEffect(() => { + const handleMouseMove = (e: { clientX: any; clientY: any; }) => { + setPosition({ x: e.clientX, y: e.clientY }); + }; + window.addEventListener('mousemove', handleMouseMove); + return () => window.removeEventListener('mousemove', handleMouseMove); + }, []); -export default function Home() { + return ( + + ); +}; + +type ShimmerButtonProps = React.ButtonHTMLAttributes & MotionProps; + +const ShimmerButton: React.FC = ({ children, ...props }) => ( + + + {children} + +); +export default function Home() { const [isDialogOpen, setIsDialogOpen] = useState(false); - const qrCodeRef = useRef(null); - const { setTheme } = useTheme() - const [input, setInput] = useState("") - const [id, setId] = useState("") + const [input, setInput] = useState(""); + const [id, setId] = useState(""); + const qrCodeRef = useRef(null); + const { setTheme } = useTheme(); - setTheme("dark") + setTheme("dark"); + const features = [ + { icon: Rocket, title: "Fast and Reliable", description: "Shorten your URLs instantly with unmatched reliability." }, + { icon: Shield, title: "Secure and Private", description: "Your data is safe with us. We prioritize your privacy." }, + { icon: ChartBar, title: "Analytics", description: "Track and analyze the performance of your shortened URLs." } + ]; + const upload = async () => { const response = await fetch('/api/upload', { method: 'POST', @@ -42,22 +94,20 @@ export default function Home() { }, body: JSON.stringify({ url: input }), }); - + const data = await response.json(); if (data.url_id) { - console.log('Generated URL ID:', data.url_id); - setId(data.url_id) - setInput("") + setId(data.url_id); + setInput(""); } else { - console.log('Error:', data.error); - setId(data.error) - } - } + setId(data.error); + } + }; const downloadQR = () => { if (!qrCodeRef.current) return; - const svg = qrCodeRef.current.querySelector("svg"); + const svg = (qrCodeRef.current as HTMLElement).querySelector("svg"); if (!svg) return; const svgData = new XMLSerializer().serializeToString(svg); const canvas = document.createElement("canvas"); @@ -82,125 +132,435 @@ export default function Home() { const handleKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') { - e.preventDefault() - upload() - setIsDialogOpen(true) + e.preventDefault(); + upload(); + setIsDialogOpen(true); } - } + }; + + const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { + staggerChildren: 0.2 + } + } + }; + + const itemVariants = { + hidden: { y: 20, opacity: 0 }, + visible: { + y: 0, + opacity: 1, + transition: { + type: "spring", + damping: 15 + } + } + }; return ( -
-
-
-

The easiest way to shorten your urls

-
- setInput(e.target.value)} - onKeyDown={handleKeyDown} - className="w-96" - type="url" - placeholder="https://example.com/" + + + +
+ + + + Shorten URLs + + Seamlessly + + + + + Shorten a link! It's free and easy to use. No credit card required. + + + + - - upload()}>Shorten! - +
+ + setInput(e.target.value)} + className="w-96 bg-zinc-800 border-zinc-700 focus:ring-white/20 transition-all duration-300" + type="url" + placeholder="https://example.com/" + /> + + + + + + + + Shorten! + + + + {id && ( <> - {id == "URL is required" ? id : "Your url was succesfully generated!"} - - {id != "URL is required" && ( - <> -
-

https://aapelix.link/{id}

-
- -
-
- -
- -
- - )} - - -
+ {id === "URL is required" ? id : "Your URL was successfully shortened!"} + + {id !== "URL is required" && ( + <> +
+

https://aapelix.link/{id}

+ +
+
+
+ +
+ +
+ + )} +
)} - {!id && ( <> - Generating your url + Generating your URL Please wait... - ) - } + )}
- redirect("https://aapelix.link/" + id)}>Go to site - Continue + {id && ( + redirect(`https://aapelix.link/${id}`)}>Go to site + )} + Close -
-
- -
- -

By shortining an url, you agree to the Terms Of Service

- +
+
+
+ + + + +
-

Read more

- + +
+ + + + +
+ + Why Choose Us? + + + {features.map((feature, index) => ( + + + + + + + {feature.title} + + +

{feature.description}

+
+
+
+ ))} +
+
+
-
-

Pricing

-
- - - - Well, actually... it's completely free! 🎉 - - - Here's what you get: - - - -
    -
  • - Infinite URLs -
  • -
  • - URLs will be deleted if unused for 3 months -
  • -
-
-
- - - - - Donations are always appreciated! ❤️ - - - Supporting keeps this service running! - - - -
    -
  • - 🌟 This service will remain free and open source forever -
  • -
  • - -
  • -
-
-
-
-
- -
+ + + + +
+
+ +

About

+

+ A modern URL shortener built with performance and simplicity in mind. Open source and free to use. +

+ + + + Support the project + + +
+ + +

Quick Links

+
    + + Terms of Service + + + Privacy Policy + + + API Documentation + + + System Status + +
+
+ + +

Connect

+ +
+ + +

Statistics

+
    + + Total URLs + 30+ + + + Active Users + 1 + + + API Calls/Day + 650+ + +
+
+
+ + + + +
+ © 2024 aapelix.link + · + + Made with + + by + + aapelix + + +
+ + + + + + + + + + + + +
+
+
+ ); -} +} \ No newline at end of file diff --git a/app/report/ticket/new/page.tsx b/app/report/ticket/new/page.tsx index 3000d0f..75561b4 100644 --- a/app/report/ticket/new/page.tsx +++ b/app/report/ticket/new/page.tsx @@ -1,5 +1,6 @@ "use client" +import { motion } from "framer-motion"; import { Card, CardContent } from "@/components/ui/card"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; @@ -10,20 +11,55 @@ import { createTicket, getUser } from "./actions"; import { Textarea } from "@/components/ui/textarea"; import { Button } from "@/components/ui/button"; import { Switch } from "@/components/ui/switch"; +import { AlertCircle, Shield, SendHorizontal } from "lucide-react"; + +const FloatingCursor = () => { + const [position, setPosition] = useState({ x: 0, y: 0 }); + + useEffect(() => { + const handleMouseMove = (e: { clientX: any; clientY: any; }) => { + setPosition({ x: e.clientX, y: e.clientY }); + }; + window.addEventListener('mousemove', handleMouseMove); + return () => window.removeEventListener('mousemove', handleMouseMove); + }, []); + + return ( + + ); +}; + +import { ReactNode } from "react"; + +const FormField = ({ children }: { children: ReactNode }) => ( + + {children} + +); function TicketForm() { const params = useSearchParams(); - const [user, setUser] = useState(null); - const [selected, setSelected] = useState(null); + const [selected, setSelected] = useState(""); const [urlId, setUrlId] = useState(""); const [description, setDescription] = useState(""); - const [connected, setConnected] = useState(false); + const [connected, setConnected] = useState(true); useEffect(() => { const a = async () => { const userData = await getUser(); - console.log(userData); setUser(userData?.email ?? null); } @@ -31,59 +67,175 @@ function TicketForm() { const url_id = params.get("url_id"); setUrlId(url_id ?? ""); - }, []) + }, []); const handleSubmit = () => { if (!urlId || !selected) return; createTicket({ email: user ?? undefined, url_id: urlId, type: selected ?? "", description }); - } + }; return ( -
-
-

Create a new ticket

- - -
- - setUser(e.target.value)} /> -
- - -
- - setUrlId(e.target.value)} value={urlId} /> - - - -