diff --git a/docs/exceptions.rst b/docs/exceptions.rst
index 4bdddb9..5f2e008 100644
--- a/docs/exceptions.rst
+++ b/docs/exceptions.rst
@@ -1,4 +1,4 @@
-Exceptions
+ Exceptions
==========
.. automodule:: shortenit.exceptions
diff --git a/frontend/package-lock.json b/frontend/package-lock.json
index 441dab0..f48f4b7 100644
--- a/frontend/package-lock.json
+++ b/frontend/package-lock.json
@@ -16,9 +16,10 @@
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"axios": "^1.7.9",
+ "framer-motion": "^11.15.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
- "react-icons": "^5.3.0",
+ "react-icons": "^5.4.0",
"react-router-dom": "^7.0.1",
"react-scripts": "5.0.1",
"react-toastify": "^11.0.1",
@@ -7850,6 +7851,32 @@
"url": "https://github.com/sponsors/rawify"
}
},
+ "node_modules/framer-motion": {
+ "version": "11.15.0",
+ "resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.15.0.tgz",
+ "integrity": "sha512-MLk8IvZntxOMg7lDBLw2qgTHHv664bYoYmnFTmE0Gm/FW67aOJk0WM3ctMcG+Xhcv+vh5uyyXwxvxhSeJzSe+w==",
+ "dependencies": {
+ "motion-dom": "^11.14.3",
+ "motion-utils": "^11.14.3",
+ "tslib": "^2.4.0"
+ },
+ "peerDependencies": {
+ "@emotion/is-prop-valid": "*",
+ "react": "^18.0.0 || ^19.0.0",
+ "react-dom": "^18.0.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@emotion/is-prop-valid": {
+ "optional": true
+ },
+ "react": {
+ "optional": true
+ },
+ "react-dom": {
+ "optional": true
+ }
+ }
+ },
"node_modules/fresh": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
@@ -10668,6 +10695,16 @@
"mkdirp": "bin/cmd.js"
}
},
+ "node_modules/motion-dom": {
+ "version": "11.14.3",
+ "resolved": "https://registry.npmjs.org/motion-dom/-/motion-dom-11.14.3.tgz",
+ "integrity": "sha512-lW+D2wBy5vxLJi6aCP0xyxTxlTfiu+b+zcpVbGVFUxotwThqhdpPRSmX8xztAgtZMPMeU0WGVn/k1w4I+TbPqA=="
+ },
+ "node_modules/motion-utils": {
+ "version": "11.14.3",
+ "resolved": "https://registry.npmjs.org/motion-utils/-/motion-utils-11.14.3.tgz",
+ "integrity": "sha512-Xg+8xnqIJTpr0L/cidfTTBFkvRw26ZtGGuIhA94J9PQ2p4mEa06Xx7QVYZH0BP+EpMSaDlu+q0I0mmvwADPsaQ=="
+ },
"node_modules/ms": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
@@ -12928,9 +12965,9 @@
"integrity": "sha512-/6UZ2qgEyH2aqzYZgQPxEnz33NJ2gNsnHA2o5+o4wW9bLM/JYQitNP9xPhsXwC08hMMovfGe/8retsdDsczPRg=="
},
"node_modules/react-icons": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz",
- "integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==",
+ "version": "5.4.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.4.0.tgz",
+ "integrity": "sha512-7eltJxgVt7X64oHh6wSWNwwbKTCtMfK35hcjvJS0yxEAhPM8oUKdS3+kqaW1vicIltw+kR2unHaa12S9pPALoQ==",
"peerDependencies": {
"react": "*"
}
diff --git a/frontend/package.json b/frontend/package.json
index b1b15be..95164d8 100644
--- a/frontend/package.json
+++ b/frontend/package.json
@@ -11,9 +11,10 @@
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"axios": "^1.7.9",
+ "framer-motion": "^11.15.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
- "react-icons": "^5.3.0",
+ "react-icons": "^5.4.0",
"react-router-dom": "^7.0.1",
"react-scripts": "5.0.1",
"react-toastify": "^11.0.1",
diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx
index bbad931..40ed2c9 100644
--- a/frontend/src/App.tsx
+++ b/frontend/src/App.tsx
@@ -1,25 +1,20 @@
import React from "react";
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
import "./App.css";
+import AppContent from "./AppContent";
// Pages & Components
-import Navbar from "./components/navbar/Navbar";
-import Footer from "./components/footer/Footer";
-import Home from "./pages/home/Home";
-import About from "./pages/about/About";
-import Contact from "./pages/contact/Contact";
+// import Navbar from "./components/navbar/Navbar";
+// import Footer from "./components/footer/Footer";
+// import Home from "./pages/home/Home";
+// import Features from "./pages/features/Features";
+// import Contact from "./pages/contact/Contact";
function App() {
return (
-
-
- } />
- } />
- } />
-
-
+
);
diff --git a/frontend/src/AppContent.tsx b/frontend/src/AppContent.tsx
new file mode 100644
index 0000000..3a9ad50
--- /dev/null
+++ b/frontend/src/AppContent.tsx
@@ -0,0 +1,26 @@
+import { BrowserRouter, Routes, Route, useLocation } from "react-router-dom";
+import "./App.css";
+import { AnimatePresence } from "framer-motion";
+
+// Pages & Components
+import Navbar from "./components/navbar/Navbar";
+import Footer from "./components/footer/Footer";
+import Home from "./pages/home/Home";
+import Features from "./pages/features/Features";
+import Contact from "./pages/contact/Contact";
+
+export default function AppContent() {
+ const location = useLocation();
+ return (
+ <>
+
+
+
+ } />
+ } />
+ } />
+
+
+ >
+ );
+}
diff --git a/frontend/src/components/URLShortener/URLShortener.css b/frontend/src/components/URLShortener/URLShortener.css
new file mode 100644
index 0000000..f2f6e30
--- /dev/null
+++ b/frontend/src/components/URLShortener/URLShortener.css
@@ -0,0 +1,157 @@
+.URLShortener-component {
+ height: 300px;
+ width: 800px;
+ border-radius: 5px;
+ box-shadow: 0px 10px 15px rgba(0, 0, 0, 0.3), 0px 4px 6px rgba(0, 0, 0, 0.1);
+ display: grid;
+ grid-template-columns: 2fr 1fr;
+ transition: box-shadow 0.3s ease-in-out;
+}
+
+.URLShortener-component:hover {
+ box-shadow: 0px 20px 25px rgba(0, 0, 0, 0.3), 0px 8px 10px rgba(0, 0, 0, 0.2);
+}
+
+.left-side {
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: flex-start;
+ gap: 10px;
+ padding-bottom: 20%;
+ padding-left: 5%;
+ padding-right: 5%;
+}
+
+.left-side h1 {
+ color: var(--color-tertiary);
+ border-bottom: 1px solid var(--color-tertiary);
+}
+
+.url-input {
+ display: flex;
+ gap: 2px;
+}
+
+.url-input input {
+ /* position: relative; */
+ width: 250px;
+ height: 40px;
+ outline: none;
+ border-radius: 5px;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ border: 1px solid rgba(0, 0, 0, 0.4);
+ padding-left: 5px;
+ white-space: nowrap;
+}
+
+.url-input button {
+ border-radius: 5px;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ background-color: var(--color-tertiary);
+ border: none;
+ min-width: 80px;
+ color: #fff;
+ transition: 0.2s;
+}
+
+.url-input button:hover {
+ opacity: 0.8;
+}
+
+.right-side {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ align-items: center;
+ text-align: center;
+ border-left: 2px solid rgba(0, 0, 0, 0.1);
+ padding: 0 5%;
+}
+
+.right-side-title h1 {
+ color: var(--color-tertiary);
+}
+
+.right-side-content p {
+ font-family: "Roboto", sans-serif;
+ font-size: 14px;
+ /* color: var(--text-color); */
+ color: #808080;
+}
+
+@media (max-width: 730px) {
+ .URLShortener-component {
+ grid-template-columns: 1fr;
+ height: auto;
+ width: auto;
+ }
+
+ .left-side {
+ padding-bottom: 5%;
+ }
+
+ .right-side {
+ border-left: none;
+ border-top: 1px solid rgba(0, 0, 0, 0.1);
+ }
+}
+
+@media (max-width: 475px) {
+ .url-input input {
+ height: 25px;
+ width: 200px;
+ }
+
+ .left-side h1 {
+ font-size: 25px;
+ }
+
+ .right-side-title h1 {
+ font-size: 25px;
+ }
+
+ .right-side-content p {
+ font-size: 13px;
+ }
+
+ .url-input button {
+ min-width: 60px;
+ }
+}
+
+@media (max-width: 475px) {
+ .url-input {
+ flex-direction: column;
+ }
+
+ .url-input button {
+ height: 30px;
+ border-radius: 5px;
+ }
+
+ .url-input input {
+ border-radius: 5px;
+ }
+}
+
+.custom-toast {
+ font-family: "Roboto", sans-serif;
+ font-size: 13px;
+}
+
+@keyframes fadeIn {
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+}
+
+.url-input.shortened {
+ opacity: 0;
+ transform: translateY(-20px);
+ animation: fadeIn 0.3s forwards;
+}
diff --git a/frontend/src/components/URLShortener/URLShortener.tsx b/frontend/src/components/URLShortener/URLShortener.tsx
new file mode 100644
index 0000000..a56dae2
--- /dev/null
+++ b/frontend/src/components/URLShortener/URLShortener.tsx
@@ -0,0 +1,112 @@
+import React, { useState } from "react";
+import "./URLShortener.css";
+import axios from "axios";
+import { ToastContainer, toast } from "react-toastify";
+import "react-toastify/dist/ReactToastify.css";
+
+export default function () {
+ const [url, setUrl] = useState("");
+ const [shortenedUrl, setShortenedUrl] = useState("");
+ const [showInput, setShowInput] = useState(false);
+
+ async function ShortenIt(e: React.FormEvent) {
+ e.preventDefault();
+
+ if (!url) {
+ toast.error("Please provide a URL", {
+ position: "top-right",
+ autoClose: 5000,
+ hideProgressBar: false,
+ closeOnClick: true,
+ pauseOnHover: true,
+ draggable: true,
+ progress: undefined,
+ theme: "dark",
+ className: "custom-toast",
+ });
+ return;
+ }
+
+ try {
+ const timestamp = Math.floor(Date.now() / 1000);
+
+ // Send the POST request to the backend
+ await axios
+ .post("http://127.0.0.1:8000/shortenit", {
+ url: url,
+ timestamp: timestamp,
+ })
+ .then((response) => {
+ if (response) {
+ const code: string = response.data.url;
+ const fullShortenedUrl: string = `http://127.0.0.1:8000/${code}`;
+ setShortenedUrl(fullShortenedUrl);
+ setShowInput(true);
+ }
+ });
+
+ setTimeout(() => {
+ setShowInput(false);
+ }, 10000);
+ } catch (error) {
+ console.log(error);
+ }
+ }
+
+ async function copyURL() {
+ try {
+ if (shortenedUrl) {
+ await navigator.clipboard.writeText(shortenedUrl);
+ toast.success("Copied to Clipboard", {
+ position: "top-right",
+ autoClose: 5000,
+ hideProgressBar: false,
+ closeOnClick: true,
+ pauseOnHover: true,
+ draggable: true,
+ progress: undefined,
+ theme: "dark",
+ className: "custom-toast",
+ });
+ }
+ } catch (error) {
+ console.log(error);
+ }
+ }
+ return (
+
+
+
Paste the URL
+
+
+ {shortenedUrl && showInput && (
+
+
+
+
+ )}
+
+
+
+
Shorten It
+
+
+
+ Shortenit is a free and open-source URL shortening service designed
+ for simplicity and efficiency.
+
+
+
+
+
+ );
+}
diff --git a/frontend/src/components/featuresCard/CardProps.ts b/frontend/src/components/featuresCard/CardProps.ts
new file mode 100644
index 0000000..1b90d81
--- /dev/null
+++ b/frontend/src/components/featuresCard/CardProps.ts
@@ -0,0 +1,8 @@
+import React from "react";
+
+export interface CardProps {
+ icon: React.ReactNode;
+ title: string;
+ description: string;
+ link : string;
+}
diff --git a/frontend/src/components/featuresCard/FeaturesCard.css b/frontend/src/components/featuresCard/FeaturesCard.css
new file mode 100644
index 0000000..55e7bb4
--- /dev/null
+++ b/frontend/src/components/featuresCard/FeaturesCard.css
@@ -0,0 +1,64 @@
+.Card {
+ position: relative;
+ height: 270px;
+ width: 250px;
+ border-radius: 10px;
+ display: grid;
+ grid-template-rows: repeat(2, 1fr);
+ overflow: hidden;
+ box-shadow: 0px 10px 15px rgba(0, 0, 0, 0.15), 0px 4px 6px rgba(0, 0, 0, 0.1);
+ font-family: "Roboto", sans-serif;
+ padding: 15px;
+ transition: .3s, transform .6s ease;
+}
+
+.Card:hover {
+ box-shadow: 0px 10px 15px rgba(0, 0, 0, 0.4), 0px 4px 6px rgba(0, 0, 0, 0.2);
+ transform: translateY(-25px);
+}
+
+
+.top-part {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+}
+
+.feature-icon {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ font-size: 30px;
+ color: var(--color-primary);
+ height: 60px;
+ width: 60px;
+ border-radius: 50%;
+ background-color: var(--color-tertiary);
+}
+
+.bottom-part {
+ text-align: center;
+}
+
+.feature-description {
+ color: #666;
+ font-size: 13px;
+}
+
+.feature-button button {
+ padding: 8px 30px;
+ border-radius: 5px;
+ background-color: #1d4ed8;
+ border: 1px solid #f5f5f5;
+ color: #fff;
+ border: none;
+ cursor: pointer;
+ transition: 0.3s;
+}
+.feature-button button a {
+ color: #fff;
+}
+
+.feature-button button:hover {
+ opacity: 0.8;
+}
diff --git a/frontend/src/components/featuresCard/FeaturesCard.tsx b/frontend/src/components/featuresCard/FeaturesCard.tsx
new file mode 100644
index 0000000..85dd4ae
--- /dev/null
+++ b/frontend/src/components/featuresCard/FeaturesCard.tsx
@@ -0,0 +1,40 @@
+import React from "react";
+import "./FeaturesCard.css";
+import { FaLink } from "react-icons/fa";
+import { Link, useNavigate } from "react-router-dom";
+import { CardProps } from "./CardProps";
+import { Navigate } from "react-router-dom";
+
+const FeaturesCard: React.FC = ({
+ icon,
+ title,
+ description,
+ link,
+}) => {
+ const navigate = useNavigate();
+ return (
+ navigate(`${link}`)}>
+
+
+
+
+
{title}
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default FeaturesCard;
diff --git a/frontend/src/components/navbar/Navbar.css b/frontend/src/components/navbar/Navbar.css
index 578ba23..8a0c5fb 100644
--- a/frontend/src/components/navbar/Navbar.css
+++ b/frontend/src/components/navbar/Navbar.css
@@ -4,6 +4,9 @@
justify-content: space-between;
align-items: center;
padding: 0 20px;
+ position: sticky;
+ top: 0;
+ z-index: 1000;
}
.logo a {
diff --git a/frontend/src/components/navbar/Navbar.tsx b/frontend/src/components/navbar/Navbar.tsx
index e279454..96b0897 100644
--- a/frontend/src/components/navbar/Navbar.tsx
+++ b/frontend/src/components/navbar/Navbar.tsx
@@ -23,7 +23,7 @@ function Navbar() {
Home
- About
+ Features
Contact
diff --git a/frontend/src/pages/about/About.css b/frontend/src/pages/about/About.css
deleted file mode 100644
index e69de29..0000000
diff --git a/frontend/src/pages/about/About.tsx b/frontend/src/pages/about/About.tsx
deleted file mode 100644
index a85d3a1..0000000
--- a/frontend/src/pages/about/About.tsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import React from "react";
-import "./About.css";
-
-function About() {
- return ABOUT PAGE
;
-}
-
-export default About;
diff --git a/frontend/src/pages/features/Features.css b/frontend/src/pages/features/Features.css
new file mode 100644
index 0000000..30a6b63
--- /dev/null
+++ b/frontend/src/pages/features/Features.css
@@ -0,0 +1,79 @@
+.features-header {
+ width: 100%;
+ text-align: center;
+ font-family: "Roboto", sans-serif;
+ background-color: var(--color-primary);
+ margin-bottom: 75px;
+}
+
+.features-header h2 {
+ font-size: 25px;
+ color: var(--color-tertiary);
+}
+
+.features-header h1 {
+ font-size: 35px;
+}
+
+/* .features-body {
+ min-height: 100vh;
+ margin: 0 10%;
+ margin-bottom: 20px;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: space-between;
+} */
+
+.features-body {
+ min-height: 100vh;
+ margin: 0 10%;
+ display: grid;
+ grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
+ grid-row-gap: 20px;
+}
+
+@media (max-width: 1466px) {
+ .features-body {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ place-items: center;
+ }
+}
+
+@media (max-width: 1076px) {
+ .features-body {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ }
+}
+
+@media (max-width: 708px) {
+ .features-body {
+ display: grid;
+ grid-template-columns: repeat(1, 1fr);
+ grid-row-gap: 20px;
+ }
+}
+
+@media (max-width: 390px) {
+ .features-body {
+ display: flex;
+ gap: 1em;
+ overflow-x: scroll;
+ scroll-snap-type: x mandatory;
+ }
+
+ .features-header {
+ margin-bottom: -50%;
+ }
+
+ .Feature-Card {
+ flex-shrink: 0;
+ aspect-ratio: 3/2;
+ scroll-snap-align: start;
+ }
+
+ .features-header h1 {
+ font-size: 25px;
+ }
+}
diff --git a/frontend/src/pages/features/Features.tsx b/frontend/src/pages/features/Features.tsx
new file mode 100644
index 0000000..19c7119
--- /dev/null
+++ b/frontend/src/pages/features/Features.tsx
@@ -0,0 +1,41 @@
+import React from "react";
+import "./Features.css";
+import FeaturesCard from "../../components/featuresCard/FeaturesCard";
+import { FaLink } from "react-icons/fa";
+import { motion } from "framer-motion";
+
+function Features() {
+ return (
+ <>
+
+ Features
+ Our Services & Features
+
+
+
+
+ }
+ title="URL Shortener"
+ description="Transform long URLs into short, shareable links in a blink of an eye."
+ link="/"
+ />
+
+
+ >
+ );
+}
+
+export default Features;
diff --git a/frontend/src/pages/home/Home.css b/frontend/src/pages/home/Home.css
index 4bb5e8a..4129f59 100644
--- a/frontend/src/pages/home/Home.css
+++ b/frontend/src/pages/home/Home.css
@@ -6,161 +6,3 @@
justify-content: center;
margin: auto;
}
-
-.home-container {
- height: 300px;
- width: 800px;
- border-radius: 5px;
- box-shadow: 0px 10px 15px rgba(0, 0, 0, 0.3), 0px 4px 6px rgba(0, 0, 0, 0.1);
- display: grid;
- grid-template-columns: 2fr 1fr;
- transition: box-shadow 0.3s ease-in-out;
-}
-
-.home-container:hover {
- box-shadow: 0px 20px 25px rgba(0, 0, 0, 0.3), 0px 8px 10px rgba(0, 0, 0, 0.2);
-}
-
-.left-side {
- position: relative;
- display: flex;
- flex-direction: column;
- align-items: center;
- justify-content: flex-start;
- gap: 10px;
- padding-bottom: 20%;
- padding-left: 5%;
- padding-right: 5%;
-}
-
-.left-side h1 {
- color: var(--color-tertiary);
- border-bottom: 1px solid var(--color-tertiary);
-}
-
-.url-input {
- display: flex;
- gap: 2px;
-}
-
-.url-input input {
- /* position: relative; */
- width: 250px;
- height: 40px;
- outline: none;
- border-radius: 5px;
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
- border: 1px solid rgba(0, 0, 0, 0.4);
- padding-left: 5px;
- white-space: nowrap;
-}
-
-.url-input button {
- border-radius: 5px;
- border-top-left-radius: 0;
- border-bottom-left-radius: 0;
- background-color: var(--color-tertiary);
- border: none;
- min-width: 80px;
- color: #fff;
- transition: 0.2s;
-}
-
-.url-input button:hover {
- opacity: 0.8;
-}
-
-.right-side {
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: center;
- text-align: center;
- border-left: 2px solid rgba(0, 0, 0, 0.1);
- padding: 0 5%;
-}
-
-.right-side-title h1 {
- color: var(--color-tertiary);
-}
-
-.right-side-content p {
- font-family: "Roboto", sans-serif;
- font-size: 14px;
- /* color: var(--text-color); */
- color: #808080;
-}
-
-@media (max-width: 730px) {
- .home-container {
- grid-template-columns: 1fr;
- height: auto;
- width: auto;
- }
-
- .left-side {
- padding-bottom: 5%;
- }
-
- .right-side {
- border-left: none;
- border-top: 1px solid rgba(0, 0, 0, 0.1);
- }
-}
-
-@media (max-width: 475px) {
- .url-input input {
- height: 25px;
- width: 200px;
- }
-
- .left-side h1 {
- font-size: 25px;
- }
-
- .right-side-title h1 {
- font-size: 25px;
- }
-
- .right-side-content p {
- font-size: 13px;
- }
-
- .url-input button {
- min-width: 60px;
- }
-}
-
-@media (max-width: 475px) {
- .url-input {
- flex-direction: column;
- }
-
- .url-input button {
- height: 30px;
- border-radius: 5px;
- }
-
- .url-input input {
- border-radius: 5px;
- }
-}
-
-.custom-toast {
- font-family: "Roboto", "sans-serif";
- font-size: 13px;
-}
-
-@keyframes fadeIn {
- to {
- opacity: 1;
- transform: translateY(0);
- }
-}
-
-.url-input.shortened {
- opacity: 0;
- transform: translateY(-20px);
- animation: fadeIn 0.3s forwards;
-}
diff --git a/frontend/src/pages/home/Home.tsx b/frontend/src/pages/home/Home.tsx
index 9e6962c..a80c5c7 100644
--- a/frontend/src/pages/home/Home.tsx
+++ b/frontend/src/pages/home/Home.tsx
@@ -1,110 +1,20 @@
-import React, { FormEvent, useState, useEffect } from "react";
+import React from "react";
import "./Home.css";
-import axios from "axios";
-import { ToastContainer, toast } from "react-toastify";
-import "react-toastify/dist/ReactToastify.css";
+import { motion } from "framer-motion";
+
+import URLShortener from "../../components/URLShortener/URLShortener";
function Home() {
- const [url, setUrl] = useState("");
- const [shortenedUrl, setShortenedUrl] = useState("");
-
- async function ShortenIt(e: React.FormEvent) {
- e.preventDefault();
-
- if (!url) {
- toast.error("Please provide a URL", {
- position: "top-right",
- autoClose: 5000,
- hideProgressBar: false,
- closeOnClick: true,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- theme: "dark",
- className: "custom-toast",
- });
- return;
- }
-
- try {
- const timestamp = Math.floor(Date.now() / 1000);
-
- // Send the POST request to the backend
- await axios
- .post("http://127.0.0.1:8000/shortenit", {
- url: url,
- timestamp: timestamp,
- })
- .then((response) => {
- if (response) {
- const code: string = response.data.url;
- const fullShortenedUrl: string = `http://127.0.0.1:8000/${code}`;
- setShortenedUrl(fullShortenedUrl);
- }
- });
- } catch (error) {
- console.log(error);
- }
- }
-
- async function copyURL() {
- try {
- if (shortenedUrl) {
- await navigator.clipboard.writeText(shortenedUrl);
- toast.success("Copied to Clipboard", {
- position: "top-right",
- autoClose: 5000,
- hideProgressBar: false,
- closeOnClick: true,
- pauseOnHover: true,
- draggable: true,
- progress: undefined,
- theme: "dark",
- className: "custom-toast",
- });
- }
- } catch (error) {
- console.log(error);
- }
- }
-
return (
-
-
-
-
Paste the URL
-
-
- {shortenedUrl && (
-
-
-
-
- )}
-
-
-
-
Shorten It
-
-
-
- Shortenit is a free and open-source URL shortening service
- designed for simplicity and efficiency.
-
-
-
-
-
-
+
+
+
);
}