[#17] Now have a download button to download a podcast episode.
This commit is contained in:
parent
34539a16df
commit
5dfc18b22e
1
public/icons/download.svg
Normal file
1
public/icons/download.svg
Normal file
@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><svg width="24px" height="24px" stroke-width="1.5" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" color="#000000"><path d="M6 20L18 20" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path><path d="M12 4V16M12 16L15.5 12.5M12 16L8.5 12.5" stroke="#000000" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"></path></svg>
|
||||
|
After Width: | Height: | Size: 430 B |
@ -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({
|
||||
<p>By: {author}</p>
|
||||
<p>Uploaded: {uploadDate}</p>
|
||||
</div>
|
||||
<div className="flex">
|
||||
<a href={url} target="_blank" rel="noopener noreferrer" className="mt-4 text-blue-500 hover:underline text-sm">
|
||||
Listen Now
|
||||
</a>
|
||||
{url &&
|
||||
<DownloadButton
|
||||
href={url}
|
||||
iconSrc={`${process.env.NEXT_PUBLIC_API_BASE_URL}/icons/download.svg`}
|
||||
iconAlt="Download"
|
||||
text="Download"
|
||||
download={`${title}-${url.split('/').pop()}`}
|
||||
className="mt-4 ml-2"
|
||||
debounceMs={2000}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -54,7 +54,6 @@ export default function StreamPublishForm({ stream }: { stream?: string | string
|
||||
};
|
||||
|
||||
xhr.send(formData);
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
50
src/app/common/components/buttons/DownloadButton.tsx
Normal file
50
src/app/common/components/buttons/DownloadButton.tsx
Normal file
@ -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<HTMLButtonElement>) => {
|
||||
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 (
|
||||
<IconExpandTextButton
|
||||
iconSrc={iconSrc}
|
||||
iconAlt={iconAlt}
|
||||
text={text}
|
||||
className={className}
|
||||
debounceMs={debounceMs}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
/>
|
||||
);
|
||||
}
|
||||
53
src/app/common/components/buttons/IconExpandTextButton.tsx
Normal file
53
src/app/common/components/buttons/IconExpandTextButton.tsx
Normal file
@ -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<HTMLAnchorElement>) => 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<HTMLAnchorElement>) => {
|
||||
e.preventDefault();
|
||||
if (disabled || debounced) return;
|
||||
if (debounceMs != null) {
|
||||
setDebounced(true);
|
||||
setTimeout(() => setDebounced(false), debounceMs);
|
||||
}
|
||||
onClick?.(e);
|
||||
};
|
||||
|
||||
return (
|
||||
<a
|
||||
download={download}
|
||||
className={`flex items-center group transition-all duration-200 bg-transparent rounded-sm hover:bg-purple-400 hover:shadow pl-1 pr-2 py-1 text-sm select-none ${className}`}
|
||||
onClick={handleClick}
|
||||
tabIndex={isDisabled ? -1 : 0}
|
||||
aria-disabled={isDisabled}
|
||||
>
|
||||
<Image src={iconSrc} alt={iconAlt} width={20} height={20} />
|
||||
<span className="overflow-hidden max-w-0 group-hover:max-w-[80px] transition-all duration-200 whitespace-nowrap ml-1">
|
||||
{text}
|
||||
</span>
|
||||
</a>
|
||||
);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user