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 axios from "axios";
|
||||||
import { v4 as uuidv4 } from "uuid";
|
import { v4 as uuidv4 } from "uuid";
|
||||||
import Confetti from "react-confetti";
|
import Confetti from "react-confetti";
|
||||||
|
import Notification from "./Notification";
|
||||||
|
|
||||||
const DownloadForm = () => {
|
const DownloadForm = () => {
|
||||||
const [url, setUrl] = useState("");
|
const [url, setUrl] = useState("");
|
||||||
@@ -10,6 +11,7 @@ const DownloadForm = () => {
|
|||||||
const [progress, setProgress] = useState(0);
|
const [progress, setProgress] = useState(0);
|
||||||
const [isDownloading, setIsDownloading] = useState(false);
|
const [isDownloading, setIsDownloading] = useState(false);
|
||||||
const [showConfetti, setShowConfetti] = useState(false);
|
const [showConfetti, setShowConfetti] = useState(false);
|
||||||
|
const [notification, setNotification] = useState(null);
|
||||||
|
|
||||||
const isValidYouTubeUrl = (url) => {
|
const isValidYouTubeUrl = (url) => {
|
||||||
const youtubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+$/;
|
const youtubeRegex = /^(https?:\/\/)?(www\.)?(youtube\.com|youtu\.be)\/.+$/;
|
||||||
@@ -20,10 +22,10 @@ const DownloadForm = () => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
if (!url) {
|
if (!url) {
|
||||||
setMessage("maybe enter an URL first");
|
setNotification("Maybe enter an URL first");
|
||||||
return;
|
return;
|
||||||
} else if (!isValidYouTubeUrl(url)) {
|
} else if (!isValidYouTubeUrl(url)) {
|
||||||
setMessage("doesn't look like YouTube to me");
|
setNotification("Doesn't look like YouTube to me");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,13 +164,13 @@ const DownloadForm = () => {
|
|||||||
{!isDownloading && !message.startsWith("Downloading") && (
|
{!isDownloading && !message.startsWith("Downloading") && (
|
||||||
<button
|
<button
|
||||||
type="submit"
|
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>
|
<span className="absolute inset-0 bg-black opacity-0 transition-opacity duration-300 ease-in-out active:opacity-40 rounded-xl"></span>
|
||||||
Download
|
Download
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>{" "}
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{showConfetti && (
|
{showConfetti && (
|
||||||
@@ -185,6 +187,12 @@ const DownloadForm = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{notification && (
|
||||||
|
<Notification
|
||||||
|
message={notification}
|
||||||
|
onClose={() => setNotification(null)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<style jsx>{`
|
<style jsx>{`
|
||||||
@keyframes loading {
|
@keyframes loading {
|
||||||
0% {
|
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