mirror of
https://github.com/arkorty/DownLink.git
synced 2026-03-17 16:51:45 +00:00
Add a simple notification component
This commit is contained in:
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react";
|
||||
import axios from "axios";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import Confetti from "react-confetti";
|
||||
import Notification from "./Notification";
|
||||
|
||||
const DownloadForm = () => {
|
||||
const [url, setUrl] = useState("");
|
||||
@@ -10,6 +11,7 @@ const DownloadForm = () => {
|
||||
const [progress, setProgress] = useState(0);
|
||||
const [isDownloading, setIsDownloading] = useState(false);
|
||||
const [showConfetti, setShowConfetti] = useState(false);
|
||||
const [notification, setNotification] = useState(null);
|
||||
|
||||
const isValidYouTubeUrl = (url) => {
|
||||
const youtubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+$/;
|
||||
@@ -20,10 +22,10 @@ const DownloadForm = () => {
|
||||
e.preventDefault();
|
||||
|
||||
if (!url) {
|
||||
setMessage("maybe enter an URL first");
|
||||
setNotification("Maybe enter an URL first");
|
||||
return;
|
||||
} else if (!isValidYouTubeUrl(url)) {
|
||||
setMessage("doesn't look like YouTube to me");
|
||||
setNotification("Doesn't look like YouTube to me");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -162,13 +164,13 @@ const DownloadForm = () => {
|
||||
{!isDownloading && !message.startsWith("Downloading") && (
|
||||
<button
|
||||
type="submit"
|
||||
className="relative inline-flex items-center px-8 py-4 text-lg font-bold rounded-xl text-white bg-black bg-opacity-60 hover:shadow-lg focus:outline-none transition-all duration-300"
|
||||
className="relative inline-flex items-center px-10 py-6 text-2xl font-bold rounded-2xl text-black bg-white bg-opacity-60 hover:shadow-lg focus:outline-none transition-all duration-300"
|
||||
>
|
||||
<span className="absolute inset-0 bg-black opacity-0 transition-opacity duration-300 ease-in-out active:opacity-40 rounded-xl"></span>
|
||||
Download
|
||||
</button>
|
||||
)}
|
||||
</div>{" "}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
{showConfetti && (
|
||||
@@ -185,6 +187,12 @@ const DownloadForm = () => {
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{notification && (
|
||||
<Notification
|
||||
message={notification}
|
||||
onClose={() => setNotification(null)}
|
||||
/>
|
||||
)}
|
||||
<style jsx>{`
|
||||
@keyframes loading {
|
||||
0% {
|
||||
|
||||
57
frontend/src/components/Notification.js
Normal file
57
frontend/src/components/Notification.js
Normal file
@@ -0,0 +1,57 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
|
||||
const Notification = ({ message, onClose }) => {
|
||||
const [fade, setFade] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const fadeOutTimer = setTimeout(() => setFade(true), 4800);
|
||||
const closeTimer = setTimeout(onClose, 5000);
|
||||
|
||||
return () => {
|
||||
clearTimeout(fadeOutTimer);
|
||||
clearTimeout(closeTimer);
|
||||
};
|
||||
}, [onClose]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`fixed top-20 right-4 z-50 ${
|
||||
fade ? "animate-fadeOut" : "animate-slideIn"
|
||||
}`}
|
||||
onClick={onClose}
|
||||
>
|
||||
<div className="bg-amber-600 text-white px-4 py-2 rounded shadow-lg cursor-pointer">
|
||||
{message}
|
||||
</div>
|
||||
<style jsx>{`
|
||||
.animate-slideIn {
|
||||
animation: slideIn 0.5s ease-out;
|
||||
}
|
||||
|
||||
.animate-fadeOut {
|
||||
animation: fadeOut 0.2s ease-in forwards;
|
||||
}
|
||||
|
||||
@keyframes slideIn {
|
||||
from {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
to {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes fadeOut {
|
||||
from {
|
||||
opacity: 1;
|
||||
}
|
||||
to {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Notification;
|
||||
Reference in New Issue
Block a user