diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..017922d --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Abhijeet Kumar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/client/src/Components/Footer.tsx b/client/src/Components/Footer.tsx new file mode 100644 index 0000000..2b13af9 --- /dev/null +++ b/client/src/Components/Footer.tsx @@ -0,0 +1,16 @@ +import Image from "next/image"; +import logo from "./../../public/chain.png"; + +const Footer = () => { + return ( + + ); +}; + +export default Footer; diff --git a/client/src/Components/Navbar.tsx b/client/src/Components/Navbar.tsx new file mode 100644 index 0000000..b47f7a2 --- /dev/null +++ b/client/src/Components/Navbar.tsx @@ -0,0 +1,106 @@ +"use client"; +import Link from "next/link"; +import { Hamburger } from "@/icons/Hamburger"; +import { useState } from "react"; +import Image from "next/image"; +import logo from "./../../public/chain.png"; + +const Navbar = () => { + const [hamburgerClick, setHamburgerClick] = useState(false); + + return ( + + ); +}; + +export default Navbar; diff --git a/client/src/components/ThemeToggle.tsx b/client/src/Components/ThemeToggle.tsx similarity index 100% rename from client/src/components/ThemeToggle.tsx rename to client/src/Components/ThemeToggle.tsx diff --git a/client/src/app/about/page.tsx b/client/src/app/about/page.tsx new file mode 100644 index 0000000..13854fb --- /dev/null +++ b/client/src/app/about/page.tsx @@ -0,0 +1,143 @@ +import { About1 } from "@/icons/Person"; +import { About2 } from "@/icons/ColorfulRocket"; +import { About3 } from "@/icons/ThinkingGirl"; +import { About4 } from "@/icons/TeamWork"; +import { About5 } from "@/icons/Robot"; + +const About = () => { + return ( +
+
+
+ +
+
+

+ About Us +

+

+ Welcome to Short.URL, an open-source URL shortener designed to + provide fast, reliable, and customizable link shortening services. + Whether you're sharing links on social media, in emails, or in + chat messages, our service makes it easy to transform those lengthy + URLs into sleek and manageable short links. +

+
+
+ +
+
+

+ Our Mission +

+

+ Our mission is to provide a powerful yet easy-to-use tool that + empowers users to take control of their links. We believe in the + power of open source and the community-driven development process. + By making [Project Name] open source, we invite developers from + around the world to contribute, improve, and innovate, ensuring that + our tool remains cutting-edge and accessible to everyone. +

+
+
+ +
+
+ +
+
+
+ +
+
+
+

+ Why Choose Short.URL? +

+
    +
  • + Open Source and Free: Our project is fully open source, which + means it's free to use, and anyone can contribute to its + development. +
  • +
  • + Community-Driven: Join a vibrant community of developers and users + who are dedicated to improving the project. +
  • +
  • + Secure and Reliable: Built with security in mind, ensuring your + data is protected. +
  • +
+
+
+ +
+
+

+ How It Works +

+

+ Using Short.URL is straightforward: +

+
    +
  • + Enter Your URL: Paste your long URL into the input field on the + homepage. +
  • +
  • + Shorten: Click the Shorten button to generate your short link. +
  • +
  • + Share: Copy and share your new short URL anywhere. +
  • +
+
+
+ +
+
+ +
+
+ +
+
+

+ Contribute{" "} +

+

+ We welcome contributions from the community! Whether you're a + seasoned developer or new to coding, there are many ways you can + help: +

+
    +
  • + Report Bugs: Found a bug? Let us know by opening an issue on our + GitHub. +
  • +
  • + Submit Pull Requests: If you've made improvements or added + new features, submit a pull request. +
  • +
  • + Spread the Word: Share Short.URL with your network to help us grow + our community. +
  • +
+
+
+
+ ); +}; + +export default About; diff --git a/client/src/app/auth/login/page.tsx b/client/src/app/auth/login/page.tsx index e280e09..f629b42 100644 --- a/client/src/app/auth/login/page.tsx +++ b/client/src/app/auth/login/page.tsx @@ -1,5 +1,5 @@ -"use client"; -import React, { useState } from "react"; +"use client" +import { useState } from "react"; import Link from "next/link"; import { GoogleIcon } from "@/icons/GoogleIcon"; @@ -44,8 +44,8 @@ const LoginPage = () => { return (
-
-
+
+

Welcome back

diff --git a/client/src/app/auth/signup/page.tsx b/client/src/app/auth/signup/page.tsx index 1247916..fad57d9 100644 --- a/client/src/app/auth/signup/page.tsx +++ b/client/src/app/auth/signup/page.tsx @@ -1,5 +1,5 @@ "use client"; -import React, { useState } from "react"; +import { useState } from "react"; import Link from "next/link"; type FormValues = { @@ -71,8 +71,8 @@ const SignUpPage = () => { }; return ( -
-
+
+

Sign up for an account

diff --git a/client/src/app/contact/page.tsx b/client/src/app/contact/page.tsx new file mode 100644 index 0000000..0afbe16 --- /dev/null +++ b/client/src/app/contact/page.tsx @@ -0,0 +1,66 @@ +import { ContactImg } from "@/icons/ContactImg"; +import Link from "next/link"; + +const Contact = () => { + return ( +
+
+
+

+ Let's Connect +

+

+ We are an open source project, our community of developers is here + to help you +

+
+ + +
+ + +
+ + +
+
+ + + Raise an issue on GitHub + +
+
+ +
+ +
+
+
+ ); +}; +export default Contact; diff --git a/client/src/app/globals.css b/client/src/app/globals.css index 9f13c9f..cd3b927 100644 --- a/client/src/app/globals.css +++ b/client/src/app/globals.css @@ -2,26 +2,22 @@ @tailwind components; @tailwind utilities; -.light { - --background: 245, 245, 245; - --nt: 245, 245, 245; - --inv: 0, 0, 0; - --ninv: 245, 245, 245; - --tog: 156, 163, 175; - --togb: 229, 231, 235; - --notf: 75, 85, 99; - - background: rgba(var(--background)); +:root { + --foreground-rgb: 0, 0, 0; + --background-start-rgb: 214, 219, 220; + --background-end-rgb: 255, 255, 255; } -.dark { - --background: 15, 23, 42; - --nt: 30, 41, 59; - --inv: 245, 245, 245; - --ninv: 0, 0, 0; - --tog: 29, 78, 216; - --togb: 55, 65, 81; - --notf: 0, 0, 0; +@media (prefers-color-scheme: dark) { + :root { + --foreground-rgb: 255, 255, 255; + --background-start-rgb: 0, 0, 0; + --background-end-rgb: 0, 0, 0; + } +} - background: rgba(var(--background)); +@layer utilities { + .text-balance { + text-wrap: balance; + } } diff --git a/client/src/app/layout.tsx b/client/src/app/layout.tsx index d397958..fad104f 100644 --- a/client/src/app/layout.tsx +++ b/client/src/app/layout.tsx @@ -1,13 +1,14 @@ import type { Metadata } from "next"; import { Poppins } from "next/font/google"; import "./globals.css"; -import Navbar from "@/components/Navbar"; +import Navbar from "@/Components/Navbar"; +import Footer from "@/Components/Footer"; + const poppins = Poppins({ subsets: ["latin"], weight: "400" }); -import { Analytics } from "@vercel/analytics/react"; export const metadata: Metadata = { - title: "ShortURL", - description: "Short URLs, Custom Links and Analytics", + title: "Short.URL", + description: "Short URLs", icons: { icon: "/chain.png", }, @@ -15,16 +16,15 @@ export const metadata: Metadata = { export default function RootLayout({ children, -}: Readonly<{ +}: { children: React.ReactNode; -}>) { +}) { return ( - - - + + - {children} - +
{children}
+
); diff --git a/client/src/app/page.tsx b/client/src/app/page.tsx index 3cdbf8c..ea86fc1 100644 --- a/client/src/app/page.tsx +++ b/client/src/app/page.tsx @@ -1,148 +1,177 @@ -// pages/index.js or pages/home.js "use client"; -import { CopyButtonIcon } from "@/icons/CopyButtonIcon"; -import GmailIcon from "../icons/GmailIcon"; -import LinkedInIcon from "../icons/LinkedInIcon"; -import WhatsAppIcon from "../icons/WhatsAppIcon"; -import Image from "next/image"; +import { HomeTop } from "@/icons/Working"; import Link from "next/link"; -import { FormEvent, useState } from "react"; -import toast, { Toaster } from "react-hot-toast"; -import useThemeStore from "@/store/themeStore"; +import { useState, FormEvent } from "react"; +import toast from "react-hot-toast"; +import { HomeMid } from "@/icons/Texting"; +import { HomeBottom } from "@/icons/Searching"; export default function Home() { const [isSubmitting, setIsSubmitting] = useState(false); const [responseUrl, setResponseUrl] = useState(""); const [message, setMessage] = useState(false); - - const { theme } = useThemeStore(); - async function onSubmit(event: FormEvent) { event.preventDefault(); - const data = new FormData(event.currentTarget); - - //validating the given url - const givenUrl = data.get("originalUrl"); - - if (givenUrl) { - try { - setIsSubmitting(true); - setResponseUrl(""); + const formData = new FormData(event.currentTarget); + const originalUrl = formData.get("originalUrl"); - const response = await fetch(`${process.env.NEXT_PUBLIC_SERVER_URL}/`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ originalUrl: data.get("originalUrl") }), - }); + try { + setIsSubmitting(true); + setResponseUrl(""); - if (response.status == 429) { - toast.error("Too Many Requests. Please try again later."); - } else if (response.status === 400) { - toast.error("Invalid URL"); - } + const response = await fetch(`${process.env.NEXT_PUBLIC_SERVER_URL}/`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ originalUrl }), + }); - // Assuming response is JSON - const responseData = await response?.json(); - setResponseUrl(responseData); - } catch (error) { - console.log("error :", error); - } finally { - setIsSubmitting(false); + if (response.status == 429) { + toast.error("Too Many Requests. Please try again later."); + return; } + + const responseData = await response.json(); + setResponseUrl(responseData.shortenedUrl || ""); + } catch (error) { + console.log("error :", error); + } finally { + setIsSubmitting(false); } } return ( -
- -
- http -

Tired of big URLs ?

-

- Make Your URL Short -

+
+
+
+

+ Shorten your Links +

+

+ Boost your reach +

+

+ Our URL shortner helps you create custom, branded links that are + easy to share and track. Get started for free today! +

-
- - -
+ + + - {responseUrl.length > 0 && ( -
-

- Shortened URL -

-
- - {responseUrl} - - - {message && ( -
-
Copied!
-
- )} -
-
- - {/* Added WhatsApp share button */} - - - {/* Added Gmail share button */} - - - {/* Added LinkedIn share button */} - + {responseUrl && ( +
+

+ Shortened URL:{" "} + + {responseUrl} + +

+ )} + +
+ +
+ Get started for free +
+ + +
Learn More
+ +
+
+ +
+
+ +
+
+
+ +
+
+
+ +
+
+
+

+ Improve User Engagement +

+

+ Simplifies sharing long URLs across various platforms, making it + easier for users to share content with friends and followers +

+
+
    +
  • Customized branded domain
  • +
  • QR Codes
  • +
+
    +
  • Dynamic Links
  • +
  • Customized Landing Pages
  • +
+
+
+
+ +
+
+

+ Enhanced Analytics and Tracking (Coming Soon...) +

+

+ Track your link analytics and get a profile of how they perform. Get + click activity, user geographical location and referral management. +

+
+
    +
  • Event Tracking
  • +
  • A/B Testing
  • +
+
    +
  • Cross Device Attribute
  • +
  • Developer Analytics API
  • +
+
+
+
+
+
- )} -
+
+
); } diff --git a/client/src/components/Navbar.tsx b/client/src/components/Navbar.tsx deleted file mode 100644 index 3f415c1..0000000 --- a/client/src/components/Navbar.tsx +++ /dev/null @@ -1,44 +0,0 @@ -"use client"; - -import Image from "next/image"; -import ThemeToggle from "./ThemeToggle"; -import useThemeStore from "@/store/themeStore"; -import { useEffect } from "react"; - -const Navbar = () => { - const { theme, setTheme } = useThemeStore(); - - useEffect(() => { - const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") - .matches - ? "dark" - : "light"; - const storedTheme = localStorage.getItem("theme"); - - if (storedTheme === "dark" || storedTheme === "light") { - setTheme(storedTheme as "dark" | "light"); - } else { - setTheme(systemTheme); - } - }, [setTheme]); - - return ( -
-
- logo -

Short.Url

-
- -
- ); -}; - -export default Navbar; diff --git a/client/src/icons/ColorfulRocket.tsx b/client/src/icons/ColorfulRocket.tsx new file mode 100644 index 0000000..d5538f1 --- /dev/null +++ b/client/src/icons/ColorfulRocket.tsx @@ -0,0 +1,40 @@ +type Props = { + className: String; +}; + +export const About2 = ({ className }: Props) => { + return ( + + + + + + + + + + + + + + + ); +}; diff --git a/client/src/icons/ContactImg.tsx b/client/src/icons/ContactImg.tsx new file mode 100644 index 0000000..40770a4 --- /dev/null +++ b/client/src/icons/ContactImg.tsx @@ -0,0 +1,40 @@ +type Props = { + className: String; +}; +export const ContactImg = ({ className }: Props) => { + return ( + + + + + + + + + + ); +}; diff --git a/client/src/icons/Gmail.tsx b/client/src/icons/Gmail.tsx new file mode 100644 index 0000000..e2756e4 --- /dev/null +++ b/client/src/icons/Gmail.tsx @@ -0,0 +1,23 @@ +export const GmailLogo = () => { + return( + + + + + + + + + + + + + + + + + + + + ) +} \ No newline at end of file diff --git a/client/src/icons/Hamburger.tsx b/client/src/icons/Hamburger.tsx new file mode 100644 index 0000000..911561e --- /dev/null +++ b/client/src/icons/Hamburger.tsx @@ -0,0 +1,12 @@ +export const Hamburger = () => { + return ( + + + + ); +}; diff --git a/client/src/icons/Person.tsx b/client/src/icons/Person.tsx new file mode 100644 index 0000000..6aee9a0 --- /dev/null +++ b/client/src/icons/Person.tsx @@ -0,0 +1,18 @@ +type Props = { + className: any; +} +export const About1 = ({className}: Props) =>{ + return ( + + + + + + + + + + ); +}; + + diff --git a/client/src/icons/Robot.tsx b/client/src/icons/Robot.tsx new file mode 100644 index 0000000..aa2d2a2 --- /dev/null +++ b/client/src/icons/Robot.tsx @@ -0,0 +1,17 @@ +type Props = { + className: String; +} + +export const About5 = ({className}: Props) => { + return( + + + + + + + + + + ) +} diff --git a/client/src/icons/Searching.tsx b/client/src/icons/Searching.tsx new file mode 100644 index 0000000..d175c31 --- /dev/null +++ b/client/src/icons/Searching.tsx @@ -0,0 +1,19 @@ +type Props={ + height:string; + width:string; + className:string; +} + +export const HomeBottom = ({height, width, className}: Props) => { + return ( + + + + + + + + + + ) +} diff --git a/client/src/icons/TeamWork.tsx b/client/src/icons/TeamWork.tsx new file mode 100644 index 0000000..543be61 --- /dev/null +++ b/client/src/icons/TeamWork.tsx @@ -0,0 +1,18 @@ +type Props = { + className: String; +} + +export const About4 = ({className}: Props) => { + return( + + + + + + + + + + + ) +} \ No newline at end of file diff --git a/client/src/icons/Texting.tsx b/client/src/icons/Texting.tsx new file mode 100644 index 0000000..ee16b69 --- /dev/null +++ b/client/src/icons/Texting.tsx @@ -0,0 +1,20 @@ +type Props = { + height: string; + width: string; + className: string; +} +export const HomeMid = ({height, width, className}: Props) => { + return( + + + + + + + + + + + + ) +} \ No newline at end of file diff --git a/client/src/icons/ThinkingGirl.tsx b/client/src/icons/ThinkingGirl.tsx new file mode 100644 index 0000000..6a6a1d5 --- /dev/null +++ b/client/src/icons/ThinkingGirl.tsx @@ -0,0 +1,40 @@ +type Props = { + className: String; +}; + +export const About3 = ({ className }: Props) => { + return ( + + + + + + + + + + + + + + + ); +}; diff --git a/client/src/icons/WhatsAppIcon.tsx b/client/src/icons/WhatsAppIcon.tsx index 19d8e35..dbbe059 100644 --- a/client/src/icons/WhatsAppIcon.tsx +++ b/client/src/icons/WhatsAppIcon.tsx @@ -1,5 +1,3 @@ -import React from "react"; - const WhatsAppIcon = () => ( { + return ( + + + + + + + + + + + ); +}; diff --git a/client/tailwind.config.ts b/client/tailwind.config.ts index 0914b32..18590d2 100644 --- a/client/tailwind.config.ts +++ b/client/tailwind.config.ts @@ -5,6 +5,7 @@ const config: Config = { "./src/pages/**/*.{js,ts,jsx,tsx,mdx}", "./src/components/**/*.{js,ts,jsx,tsx,mdx}", "./src/app/**/*.{js,ts,jsx,tsx,mdx}", + "./src/**/*.{js,jsx,ts,tsx}", ], theme: { extend: { @@ -21,6 +22,9 @@ const config: Config = { tog: "rgba(var(--tog))", togb: "rgba(var(--togb))", notf: "rgba(var(--notf))" + }, + screens: { + 'xxl': '1200px' } }, },