a better abstraction of download buttons

This commit is contained in:
spencerwooo 2021-12-29 15:23:47 +08:00
parent 0613e035b2
commit 5bc8fc4a67
No known key found for this signature in database
GPG key ID: 24CD550268849CA0
14 changed files with 161 additions and 121 deletions

View file

@ -1,48 +0,0 @@
import { FunctionComponent } from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import toast, { Toaster } from 'react-hot-toast'
import { useRouter } from 'next/router'
import { useClipboard } from 'use-clipboard-copy'
import { getBaseUrl } from '../utils/getBaseUrl'
const DownloadBtn: FunctionComponent<{ downloadUrl: string }> = ({ downloadUrl }) => {
const { asPath } = useRouter()
const clipboard = useClipboard()
return (
<div className="flex flex-wrap justify-center space-x-2">
<Toaster />
<a
className="w-36 focus:outline-none focus:ring focus:ring-blue-300 hover:bg-blue-500 flex items-center justify-center flex-shrink-0 px-4 py-2 mb-2 space-x-4 text-white border-2 border-blue-500 rounded transition-all duration-100"
href={downloadUrl}
target="_blank"
rel="noopener noreferrer"
>
<FontAwesomeIcon icon="file-download" />
<span>Download</span>
</a>
<a
className="focus:outline-none focus:ring focus:ring-pink-300 hover:bg-pink-500 flex items-center justify-center flex-shrink-0 px-4 py-2 mb-2 space-x-4 text-white border-2 border-pink-500 rounded transition-all duration-100"
href={`/api/proxy?url=${encodeURIComponent(downloadUrl)}`}
target="_blank"
rel="noopener noreferrer"
>
<FontAwesomeIcon icon="file-download" />
<span>Proxy download</span>
</a>
<button
className="focus:outline-none focus:ring focus:ring-yellow-300 hover:bg-yellow-500 flex items-center justify-center flex-shrink-0 w-48 px-4 py-2 mb-2 space-x-4 text-white border-2 border-yellow-500 rounded transition-all duration-100"
onClick={() => {
clipboard.copy(`${getBaseUrl()}/api?path=${asPath}&raw=true`)
toast.success('Copied direct link to clipboard.')
}}
>
<FontAwesomeIcon icon="copy" />
<span>Copy direct link</span>
</button>
</div>
)
}
export default DownloadBtn

View file

@ -0,0 +1,92 @@
import { MouseEventHandler } from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { IconProp } from '@fortawesome/fontawesome-svg-core'
import toast, { Toaster } from 'react-hot-toast'
import { useClipboard } from 'use-clipboard-copy'
import Image from 'next/image'
import { useRouter } from 'next/router'
import { getBaseUrl } from '../utils/getBaseUrl'
const btnStyleMap = (btnColor?: string) => {
const colorMap = {
gray: 'hover:text-gray-600 dark:hover:text-white focus:ring-gray-200 focus:text-gray-600 dark:focus:text-white border-gray-300 dark:border-gray-500 dark:focus:ring-gray-500',
blue: 'hover:text-blue-600 focus:ring-blue-200 focus:text-blue-600 border-blue-300 dark:border-blue-700 dark:focus:ring-blue-500',
teal: 'hover:text-teal-600 focus:ring-teal-200 focus:text-teal-600 border-teal-300 dark:border-teal-700 dark:focus:ring-teal-500',
red: 'hover:text-red-600 focus:ring-red-200 focus:text-red-600 border-red-300 dark:border-red-700 dark:focus:ring-red-500',
green:
'hover:text-green-600 focus:ring-green-200 focus:text-green-600 border-green-300 dark:border-green-700 dark:focus:ring-green-500',
pink: 'hover:text-pink-600 focus:ring-pink-200 focus:text-pink-600 border-pink-300 dark:border-pink-700 dark:focus:ring-pink-500',
yellow:
'hover:text-yellow-400 focus:ring-yellow-100 focus:text-yellow-400 border-yellow-300 dark:border-yellow-400 dark:focus:ring-yellow-300',
}
if (btnColor) {
return colorMap[btnColor]
}
return colorMap.gray
}
export const DownloadButton = ({
onClickCallback,
btnColor,
btnText,
btnIcon,
btnImage,
}: {
onClickCallback: MouseEventHandler<HTMLButtonElement>
btnColor?: string
btnText: string
btnIcon?: IconProp
btnImage?: string
}) => {
return (
<button
className={`flex items-center space-x-2 py-2 px-4 text-sm font-medium text-gray-900 bg-white rounded-lg border hover:bg-gray-100/10 focus:z-10 focus:ring-2 dark:bg-gray-800 dark:text-gray-200 dark:hover:bg-gray-900 ${btnStyleMap(
btnColor
)}`}
onClick={onClickCallback}
>
{btnIcon && <FontAwesomeIcon icon={btnIcon} />}
{btnImage && <Image src={btnImage} alt={btnImage} width={20} height={20} />}
<span>{btnText}</span>
</button>
)
}
const DownloadButtonGroup: React.FC<{ downloadUrl: string }> = ({ downloadUrl }) => {
const { asPath } = useRouter()
const clipboard = useClipboard()
return (
<div className="flex flex-wrap justify-center gap-2">
<Toaster />
<DownloadButton
onClickCallback={() => window.open(downloadUrl)}
btnColor="blue"
btnText="Download"
btnIcon="file-download"
/>
<DownloadButton
onClickCallback={() => window.open(`/api/proxy?url=${encodeURIComponent(downloadUrl)}`)}
btnColor="teal"
btnText="Proxy download"
btnIcon="download"
/>
<DownloadButton
onClickCallback={() => {
clipboard.copy(`${getBaseUrl()}/api?path=${asPath}&raw=true`)
toast.success('Copied direct link to clipboard.')
}}
btnColor="yellow"
btnText="Copy direct link"
btnIcon="copy"
/>
</div>
)
}
export default DownloadButtonGroup

View file

@ -30,7 +30,7 @@ import CodePreview from './previews/CodePreview'
import OfficePreview from './previews/OfficePreview'
import AudioPreview from './previews/AudioPreview'
import VideoPreview from './previews/VideoPreview'
import DownloadBtn from './DownloadBtn'
import DownloadButtonGroup from './DownloadBtnGtoup'
import PDFPreview from './previews/PDFPreview'
// Disabling SSR for some previews (image gallery view, and PDF view)
@ -592,7 +592,7 @@ const FileListing: FunctionComponent<{ query?: ParsedUrlQuery }> = ({ query }) =
/>
</div>
<div className="mt-4">
<DownloadBtn downloadUrl={downloadUrl} />
<DownloadButtonGroup downloadUrl={downloadUrl} />
</div>
</>
)

View file

@ -3,20 +3,20 @@ import { FunctionComponent } from 'react'
const FourOhFour: FunctionComponent<{ errorMsg: string }> = ({ errorMsg }) => {
return (
<div className="my-20">
<div className="md:w-1/3 w-1/2 mx-auto">
<div className="my-12">
<div className="md:w-1/4 w-1/3 mx-auto">
<Image src={'/images/empty.png'} alt="404" width={912} height={912} />
</div>
<div className="mt-6 text-gray-500 max-w-xl mx-auto">
<div className="text-2xl font-bold mb-8">
<div className="text-xl font-bold mb-8">
Oops, that&apos;s a <span className="underline decoration-wavy decoration-red-500">four-oh-four</span>.
</div>
<div className="font-mono border border-gray-400/20 rounded p-2 mb-4 text-sm bg-gray-50 dark:bg-gray-800">
<div className="font-mono border border-gray-400/20 rounded p-2 mb-4 text-xs bg-gray-50 dark:bg-gray-800">
{errorMsg}
</div>
<div>
<div className="text-sm">
Press{' '}
<kbd className="border-opacity-20 font-mono text-sm p-1 bg-gray-100 dark:bg-gray-800 border rounded">F12</kbd>{' '}
<kbd className="border-opacity-20 font-mono text-xs p-1 bg-gray-100 dark:bg-gray-800 border rounded">F12</kbd>{' '}
and open devtools for more details, or seek help at{' '}
<a
className="text-blue-600 hover:text-blue-700 hover:underline"

View file

@ -62,21 +62,23 @@ const Navbar = () => {
className="flex items-center space-x-2 dark:text-white hover:opacity-80"
>
<FontAwesomeIcon icon={['fab', l.name.toLowerCase() as IconName]} />
<span className="text-sm hidden md:inline-block">{l.name}</span>
<span className="text-sm font-medium hidden md:inline-block">{l.name}</span>
</a>
))}
<a href={siteConfig.email} className="flex items-center space-x-2 dark:text-white hover:opacity-80">
<FontAwesomeIcon icon={['far', 'envelope']} />
<span className="text-sm hidden md:inline-block">Email</span>
</a>
{siteConfig.email && (
<a href={siteConfig.email} className="flex items-center space-x-2 dark:text-white hover:opacity-80">
<FontAwesomeIcon icon={['far', 'envelope']} />
<span className="text-sm font-medium hidden md:inline-block">Email</span>
</a>
)}
{tokenPresent && (
<button
className="hover:bg-gray-200 dark:text-white dark:hover:bg-gray-700 flex items-center p-2 space-x-2 rounded"
onClick={() => setIsOpen(true)}
>
<span className="text-sm">Logout</span>
<span className="text-sm font-medium">Logout</span>
<FontAwesomeIcon icon="sign-out-alt" />
</button>
)}

View file

@ -2,7 +2,7 @@ import { FunctionComponent, useState } from 'react'
import ReactPlayer from 'react-player'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import DownloadBtn from '../DownloadBtn'
import DownloadButtonGroup from '../DownloadBtnGtoup'
enum PlayerState {
Loading,
@ -74,7 +74,7 @@ const AudioPreview: FunctionComponent<{ file: any }> = ({ file }) => {
</div>
</div>
<div className="mt-4">
<DownloadBtn downloadUrl={file['@microsoft.graph.downloadUrl']} />
<DownloadButtonGroup downloadUrl={file['@microsoft.graph.downloadUrl']} />
</div>
</>
)

View file

@ -5,7 +5,7 @@ import { getExtension } from '../../utils/getFileIcon'
import { useStaleSWR } from '../../utils/fetchWithSWR'
import FourOhFour from '../FourOhFour'
import Loading from '../Loading'
import DownloadBtn from '../DownloadBtn'
import DownloadButtonGroup from '../DownloadBtnGtoup'
const CodePreview: FunctionComponent<{ file: any }> = ({ file }) => {
const { data, error } = useStaleSWR({ url: file['@microsoft.graph.downloadUrl'] })
@ -39,7 +39,7 @@ const CodePreview: FunctionComponent<{ file: any }> = ({ file }) => {
</pre>
</div>
<div className="mt-4">
<DownloadBtn downloadUrl={file['@microsoft.graph.downloadUrl']} />
<DownloadButtonGroup downloadUrl={file['@microsoft.graph.downloadUrl']} />
</div>
</>
)

View file

@ -3,7 +3,7 @@ import { ReactReader } from 'react-reader'
import type { Rendition } from 'epubjs'
import Loading from '../Loading'
import DownloadBtn from '../DownloadBtn'
import DownloadButtonGroup from '../DownloadBtnGtoup'
const EPUBPreview: FunctionComponent<{file: any}> = ({ file }) => {
const [epubContainerWidth, setEpubContainerWidth] = useState(400)
@ -52,7 +52,7 @@ const EPUBPreview: FunctionComponent<{file: any}> = ({ file }) => {
</div>
</div>
<div className="mt-4">
<DownloadBtn downloadUrl={file['@microsoft.graph.downloadUrl']} />
<DownloadButtonGroup downloadUrl={file['@microsoft.graph.downloadUrl']} />
</div>
</>
)

View file

@ -10,7 +10,7 @@ import 'katex/dist/katex.min.css'
import FourOhFour from '../FourOhFour'
import Loading from '../Loading'
import DownloadBtn from '../DownloadBtn'
import DownloadButtonGroup from '../DownloadBtnGtoup'
import { useStaleSWR } from '../../utils/fetchWithSWR'
const MarkdownPreview: FunctionComponent<{ file: any; path: string; standalone?: boolean }> = ({
@ -100,7 +100,7 @@ const MarkdownPreview: FunctionComponent<{ file: any; path: string; standalone?:
</div>
{standalone && (
<div className="mt-4">
<DownloadBtn downloadUrl={file['@microsoft.graph.downloadUrl']} />
<DownloadButtonGroup downloadUrl={file['@microsoft.graph.downloadUrl']} />
</div>
)}
</>

View file

@ -1,7 +1,7 @@
import { FunctionComponent, useEffect, useRef, useState } from 'react'
import Preview from 'preview-office-docs'
import DownloadBtn from '../DownloadBtn'
import DownloadButtonGroup from '../DownloadBtnGtoup'
const OfficePreview: FunctionComponent<{ file: any }> = ({ file }) => {
const docContainer = useRef<HTMLDivElement>(null)
@ -17,7 +17,7 @@ const OfficePreview: FunctionComponent<{ file: any }> = ({ file }) => {
<Preview url={encodeURIComponent(file['@microsoft.graph.downloadUrl'])} width={docContainerWidth.toString()} height="800" />
</div>
<div className="mt-4">
<DownloadBtn downloadUrl={file['@microsoft.graph.downloadUrl']} />
<DownloadButtonGroup downloadUrl={file['@microsoft.graph.downloadUrl']} />
</div>
</>
)

View file

@ -1,6 +1,6 @@
import { FunctionComponent } from 'react'
import DownloadBtn from '../DownloadBtn'
import DownloadButtonGroup from '../DownloadBtnGtoup'
const PDFEmbedPreview: FunctionComponent<{ file: any }> = ({ file }) => {
// const url = `/api/proxy?url=${encodeURIComponent(file['@microsoft.graph.downloadUrl'])}&inline=true`
@ -14,7 +14,7 @@ const PDFEmbedPreview: FunctionComponent<{ file: any }> = ({ file }) => {
<iframe src={url} frameBorder="0" width="100%" height="100%"></iframe>
</div>
<div className="mt-4">
<DownloadBtn downloadUrl={file['@microsoft.graph.downloadUrl']} />
<DownloadButtonGroup downloadUrl={file['@microsoft.graph.downloadUrl']} />
</div>
</>
)

View file

@ -2,7 +2,7 @@ import { FunctionComponent } from 'react'
import FourOhFour from '../FourOhFour'
import Loading from '../Loading'
import DownloadBtn from '../DownloadBtn'
import DownloadButtonGroup from '../DownloadBtnGtoup'
import { useStaleSWR } from '../../utils/fetchWithSWR'
const TextPreview: FunctionComponent<{ file: any }> = ({ file }) => {
@ -28,7 +28,7 @@ const TextPreview: FunctionComponent<{ file: any }> = ({ file }) => {
<pre className="md:p-3 p-0 overflow-scroll">{data}</pre>
</div>
<div className="mt-4">
<DownloadBtn downloadUrl={file['@microsoft.graph.downloadUrl']} />
<DownloadButtonGroup downloadUrl={file['@microsoft.graph.downloadUrl']} />
</div>
</>
)

View file

@ -7,6 +7,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import toast, { Toaster } from 'react-hot-toast'
import { getBaseUrl } from '../../utils/getBaseUrl'
import { DownloadButton } from '../DownloadBtnGtoup'
const VideoPreview: FunctionComponent<{ file: any }> = ({ file }) => {
const { asPath } = useRouter()
@ -25,56 +26,48 @@ const VideoPreview: FunctionComponent<{ file: any }> = ({ file }) => {
/>
</div>
<div className="flex flex-wrap justify-center mt-4 space-x-2">
<div className="flex flex-wrap justify-center mt-4 gap-2">
<Toaster />
<a
className="w-36 focus:outline-none focus:ring focus:ring-blue-300 hover:bg-blue-400 flex items-center justify-center flex-shrink-0 px-4 py-2 mb-2 space-x-4 text-white bg-blue-500 rounded"
href={file['@microsoft.graph.downloadUrl']}
target="_blank"
rel="noopener noreferrer"
>
<FontAwesomeIcon icon="file-download" />
<span>Download</span>
</a>
<button
className="focus:outline-none focus:ring focus:ring-yellow-300 hover:bg-yellow-400 flex items-center justify-center flex-shrink-0 w-48 px-4 py-2 mb-2 space-x-4 text-white bg-yellow-500 rounded"
onClick={() => {
<DownloadButton
onClickCallback={() => window.open(file['@microsoft.graph.downloadUrl'])}
btnColor="blue"
btnText="Download"
btnIcon="file-download"
/>
<DownloadButton
onClickCallback={() =>
window.open(`/api/proxy?url=${encodeURIComponent(file['@microsoft.graph.downloadUrl'])}`)
}
btnColor="pink"
btnText="Proxy download"
btnIcon="download"
/>
<DownloadButton
onClickCallback={() => {
clipboard.copy(`${getBaseUrl()}/api?path=${asPath}&raw=true`)
toast.success('Copied direct link to clipboard.')
}}
>
<FontAwesomeIcon icon="copy" />
<span>Copy direct link</span>
</button>
btnColor="yellow"
btnText="Copy direct link"
btnIcon="copy"
/>
<a
className="focus:outline-none focus:ring focus:ring-gray-300 hover:bg-gray-600 flex items-center justify-center px-4 py-2 mb-2 space-x-2 text-white bg-gray-700 rounded"
href={`iina://weblink?url=${file['@microsoft.graph.downloadUrl']}`}
target="_blank"
rel="noopener noreferrer"
>
<Image src="/players/iina.png" alt="iina" width="28" height="28" />
<span>IINA</span>
</a>
<a
className="focus:outline-none focus:ring focus:ring-yellow-300 hover:bg-yellow-500 flex items-center justify-center px-4 py-2 mb-2 space-x-2 text-white bg-yellow-600 rounded"
href={`vlc://${file['@microsoft.graph.downloadUrl']}`}
target="_blank"
rel="noopener noreferrer"
>
<Image src="/players/vlc.png" alt="vlc" width="28" height="28" />
<span>VLC</span>
</a>
<a
className="focus:outline-none focus:ring focus:ring-yellow-100 hover:bg-yellow-300 flex items-center justify-center px-4 py-2 mb-2 space-x-2 text-white bg-yellow-400 rounded"
href={`potplayer://${file['@microsoft.graph.downloadUrl']}`}
target="_blank"
rel="noopener noreferrer"
>
<Image src="/players/potplayer.png" alt="potplayer" width="28" height="28" />
<span>PotPlayer</span>
</a>
<DownloadButton
onClickCallback={() => window.open(`iina://weblink?url=${file['@microsoft.graph.downloadUrl']}`)}
btnText="IINA"
btnImage="/players/iina.png"
/>
<DownloadButton
onClickCallback={() => window.open(`vlc://${file['@microsoft.graph.downloadUrl']}`)}
btnText="VLC"
btnImage="/players/vlc.png"
/>
<DownloadButton
onClickCallback={() => window.open(`potplayer://${file['@microsoft.graph.downloadUrl']}`)}
btnText="PotPlayer"
btnImage="/players/potplayer.png"
/>
</div>
</>
)

View file

@ -18,7 +18,8 @@ module.exports = {
blue: colors.sky,
indigo: colors.indigo,
purple: colors.purple,
pink: colors.pink
pink: colors.pink,
teal: colors.teal
},
extend: {
fontFamily: {