diff --git a/public/icons/download.svg b/public/icons/download.svg
new file mode 100644
index 0000000..7946531
--- /dev/null
+++ b/public/icons/download.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/app/[stream]/podcasts/podcastCard.tsx b/src/app/[stream]/podcasts/podcastCard.tsx
index a0aeb79..58f695e 100644
--- a/src/app/[stream]/podcasts/podcastCard.tsx
+++ b/src/app/[stream]/podcasts/podcastCard.tsx
@@ -1,8 +1,9 @@
"use client";
import Image from 'next/image';
-import { PodcastDto } from '../../../common/dtos/podcastDto';
+import { PodcastDto } from '@/common/dtos/podcastDto';
import { useState } from 'react';
+import DownloadButton from '@/app/common/components/buttons/DownloadButton';
export default function PodcastCard({
imageUrl = "https://placehold.co/400",
@@ -40,9 +41,22 @@ export default function PodcastCard({
By: {author}
Uploaded: {uploadDate}
-
- Listen Now
-
+
);
diff --git a/src/app/[stream]/publish/publishForm.tsx b/src/app/[stream]/publish/publishForm.tsx
index 15befd0..bc1d68a 100644
--- a/src/app/[stream]/publish/publishForm.tsx
+++ b/src/app/[stream]/publish/publishForm.tsx
@@ -54,7 +54,6 @@ export default function StreamPublishForm({ stream }: { stream?: string | string
};
xhr.send(formData);
-
}
return (
diff --git a/src/app/common/components/buttons/DownloadButton.tsx b/src/app/common/components/buttons/DownloadButton.tsx
new file mode 100644
index 0000000..5bfb31f
--- /dev/null
+++ b/src/app/common/components/buttons/DownloadButton.tsx
@@ -0,0 +1,50 @@
+"use client";
+
+import IconExpandTextButton from "./IconExpandTextButton";
+
+type DownloadButtonProps = {
+ href: string;
+ iconSrc: string;
+ iconAlt?: string;
+ text: string;
+ download?: boolean | string;
+ className?: string;
+ debounceMs?: number;
+ disabled?: boolean;
+};
+
+export default function DownloadButton({
+ href,
+ iconSrc,
+ iconAlt = "icon",
+ text,
+ download = false,
+ className = "",
+ debounceMs,
+ disabled = false
+}: DownloadButtonProps) {
+ const onClick = (e: React.MouseEvent) => {
+ e.preventDefault();
+ if (disabled) return;
+
+ const link = document.createElement("a");
+ link.href = href;
+ if (download) {
+ link.setAttribute('download', typeof download === 'string' ? download : '');
+ }
+ document.body.appendChild(link);
+ link.click();
+ document.body.removeChild(link);
+ };
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/src/app/common/components/buttons/IconExpandTextButton.tsx b/src/app/common/components/buttons/IconExpandTextButton.tsx
new file mode 100644
index 0000000..9b6f483
--- /dev/null
+++ b/src/app/common/components/buttons/IconExpandTextButton.tsx
@@ -0,0 +1,53 @@
+"use client";
+
+import { useState } from "react";
+import Image from "next/image";
+
+type IconExpandTextButtonProps = {
+ iconSrc: string;
+ iconAlt?: string;
+ text: string;
+ download?: boolean | string;
+ className?: string;
+ debounceMs?: number;
+ onClick?: (e: React.MouseEvent) => void;
+ disabled?: boolean;
+};
+
+export default function IconExpandTextButton({
+ iconSrc,
+ iconAlt = "icon",
+ text,
+ download = false,
+ className = "",
+ debounceMs,
+ onClick,
+ disabled = false
+}: IconExpandTextButtonProps) {
+ const [debounced, setDebounced] = useState(false),
+ isDisabled = disabled || debounced,
+ handleClick = (e: React.MouseEvent) => {
+ e.preventDefault();
+ if (disabled || debounced) return;
+ if (debounceMs != null) {
+ setDebounced(true);
+ setTimeout(() => setDebounced(false), debounceMs);
+ }
+ onClick?.(e);
+ };
+
+ return (
+
+
+
+ {text}
+
+
+ );
+}
\ No newline at end of file