customise embed link menu, close #314

This commit is contained in:
spencerwooo
2022-02-12 22:09:54 +08:00
parent fe38825649
commit c6abeeb8aa
6 changed files with 171 additions and 21 deletions
+109
View File
@@ -0,0 +1,109 @@
import { Dispatch, Fragment, SetStateAction, useState } from 'react'
import toast from 'react-hot-toast'
import { useTranslation } from 'next-i18next'
import { Dialog, Transition } from '@headlessui/react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { useClipboard } from 'use-clipboard-copy'
import { getBaseUrl } from '../utils/getBaseUrl'
export default function CustomEmbedLinkMenu({
path,
menuOpen,
setMenuOpen,
}: {
path: string
menuOpen: boolean
setMenuOpen: Dispatch<SetStateAction<boolean>>
}) {
const { t } = useTranslation()
const clipboard = useClipboard()
const closeMenu = () => setMenuOpen(false)
const filename = path.substring(path.lastIndexOf('/') + 1)
const [name, setName] = useState(filename)
return (
<Transition appear show={menuOpen} as={Fragment}>
<Dialog as="div" className="fixed inset-0 z-10 overflow-y-auto" onClose={closeMenu}>
<div className="min-h-screen px-4 text-center">
<Transition.Child
as={Fragment}
enter="ease-out duration-100"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Dialog.Overlay className="fixed inset-0 bg-white/60 dark:bg-gray-800/60" />
</Transition.Child>
{/* This element is to trick the browser into centering the modal contents. */}
<span className="inline-block h-screen align-middle" aria-hidden="true">
&#8203;
</span>
<Transition.Child
as={Fragment}
enter="ease-out duration-100"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="ease-in duration-100"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<div className="inline-block max-h-[80vh] w-full max-w-3xl transform overflow-hidden overflow-y-scroll rounded border border-gray-400/30 bg-white p-4 text-left align-middle text-sm shadow-xl transition-all dark:bg-gray-900 dark:text-white">
<Dialog.Title as="h3" className="py-2 text-xl font-bold">
{t('Customise direct link')}
</Dialog.Title>
<Dialog.Description as="p" className="py-2 opacity-80">
{t('Change the raw file direct link to a URL ending with the extension of the file.')}{' '}
<a
href="https://onedrive-vercel-index.spencerwoo.com/docs/features/customise-direct-link"
target="_blank"
rel="noopener noreferrer"
className="text-blue-400 underline"
>
{t('What is this?')}
</a>
</Dialog.Description>
<div className="mt-4">
<h4 className="py-2 text-xs font-medium uppercase tracking-wider">{t('Filename')}</h4>
<input
className="mb-2 w-full rounded border border-gray-600/10 p-1 font-mono focus:outline-none focus:ring focus:ring-blue-300 dark:bg-gray-600 dark:text-white dark:focus:ring-blue-700"
value={name}
onChange={e => setName(e.target.value)}
/>
<h4 className="py-2 text-xs font-medium uppercase tracking-wider">{t('Default')}</h4>
<div className="mb-2 rounded border border-gray-400/20 bg-gray-50 p-1 font-mono dark:bg-gray-800">
{`${getBaseUrl()}/api?path=${path}&raw=true`}
</div>
<h4 className="py-2 text-xs font-medium uppercase tracking-wider">{t('Customised')}</h4>
<div className="mb-2 rounded border border-gray-400/20 bg-gray-50 p-1 font-mono dark:bg-gray-800">
<span>{`${getBaseUrl()}/api/name/`}</span>
<span className="underline decoration-blue-400 decoration-wavy">{name}</span>
<span>{`?path=${path}&raw=true`}</span>
</div>
</div>
<div className="mb-2 mt-6 text-right">
<button
className="rounded-lg bg-gradient-to-r from-cyan-500 to-blue-500 px-4 py-2 text-center text-sm font-medium text-white hover:bg-gradient-to-bl focus:ring-4 focus:ring-cyan-300 dark:focus:ring-cyan-800"
onClick={() => {
clipboard.copy(`${getBaseUrl()}/api/name/${name}?path=${path}&raw=true`)
toast.success(t('Copied customised link to clipboard.'))
closeMenu()
}}
>
<FontAwesomeIcon icon="copy" />
<span className="ml-2">{t('Copy custom link to clipboard')}</span>
</button>
</div>
</div>
</Transition.Child>
</div>
</Dialog>
</Transition>
)
}
+32 -21
View File
@@ -1,4 +1,4 @@
import { MouseEventHandler } from 'react' import { MouseEventHandler, useState } from 'react'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { IconProp } from '@fortawesome/fontawesome-svg-core' import { IconProp } from '@fortawesome/fontawesome-svg-core'
import toast from 'react-hot-toast' import toast from 'react-hot-toast'
@@ -10,6 +10,7 @@ import { useRouter } from 'next/router'
import { getBaseUrl } from '../utils/getBaseUrl' import { getBaseUrl } from '../utils/getBaseUrl'
import { getReadablePath } from '../utils/getReadablePath' import { getReadablePath } from '../utils/getReadablePath'
import CustomEmbedLinkMenu from './CustomEmbedLinkMenu'
const btnStyleMap = (btnColor?: string) => { const btnStyleMap = (btnColor?: string) => {
const colorMap = { const colorMap = {
@@ -64,36 +65,46 @@ export const DownloadButton = ({
const DownloadButtonGroup: React.FC<{ downloadUrl: string }> = ({ downloadUrl }) => { const DownloadButtonGroup: React.FC<{ downloadUrl: string }> = ({ downloadUrl }) => {
const { asPath } = useRouter() const { asPath } = useRouter()
const clipboard = useClipboard() const clipboard = useClipboard()
const [menuOpen, setMenuOpen] = useState(false)
const { t } = useTranslation() const { t } = useTranslation()
return ( return (
<div className="flex flex-wrap justify-center gap-2"> <>
<DownloadButton <CustomEmbedLinkMenu menuOpen={menuOpen} setMenuOpen={setMenuOpen} path={asPath} />
onClickCallback={() => window.open(downloadUrl)} <div className="flex flex-wrap justify-center gap-2">
btnColor="blue" <DownloadButton
btnText={t('Download')} onClickCallback={() => window.open(downloadUrl)}
btnIcon="file-download" btnColor="blue"
btnTitle={t('Download the file directly through OneDrive')} btnText={t('Download')}
/> btnIcon="file-download"
{/* <DownloadButton btnTitle={t('Download the file directly through OneDrive')}
/>
{/* <DownloadButton
onClickCallback={() => window.open(`/api/proxy?url=${encodeURIComponent(downloadUrl)}`)} onClickCallback={() => window.open(`/api/proxy?url=${encodeURIComponent(downloadUrl)}`)}
btnColor="teal" btnColor="teal"
btnText={t('Proxy download')} btnText={t('Proxy download')}
btnIcon="download" btnIcon="download"
btnTitle={t('Download the file with the stream proxied through Vercel Serverless')} btnTitle={t('Download the file with the stream proxied through Vercel Serverless')}
/> */} /> */}
<DownloadButton <DownloadButton
onClickCallback={() => { onClickCallback={() => {
clipboard.copy(`${getBaseUrl()}/api?path=${getReadablePath(asPath)}&raw=true`) clipboard.copy(`${getBaseUrl()}/api?path=${getReadablePath(asPath)}&raw=true`)
toast.success(t('Copied direct link to clipboard.')) toast.success(t('Copied direct link to clipboard.'))
}} }}
btnColor="pink" btnColor="pink"
btnText={t('Copy direct link')} btnText={t('Copy direct link')}
btnIcon="copy" btnIcon="copy"
btnTitle={t('Copy the permalink to the file to the clipboard')} btnTitle={t('Copy the permalink to the file to the clipboard')}
/> />
</div> <DownloadButton
onClickCallback={() => setMenuOpen(true)}
btnColor="teal"
btnText={t('Customise link')}
btnIcon="pen"
/>
</div>
</>
) )
} }
+10
View File
@@ -1,4 +1,5 @@
import type { OdFileObject } from '../../types' import type { OdFileObject } from '../../types'
import { useState } from 'react'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { useClipboard } from 'use-clipboard-copy' import { useClipboard } from 'use-clipboard-copy'
import DPlayer from 'react-dplayer' import DPlayer from 'react-dplayer'
@@ -13,11 +14,13 @@ import { DownloadButton } from '../DownloadBtnGtoup'
import { DownloadBtnContainer, PreviewContainer } from './Containers' import { DownloadBtnContainer, PreviewContainer } from './Containers'
import FourOhFour from '../FourOhFour' import FourOhFour from '../FourOhFour'
import Loading from '../Loading' import Loading from '../Loading'
import CustomEmbedLinkMenu from '../CustomEmbedLinkMenu'
const VideoPreview: React.FC<{ file: OdFileObject }> = ({ file }) => { const VideoPreview: React.FC<{ file: OdFileObject }> = ({ file }) => {
const { asPath } = useRouter() const { asPath } = useRouter()
const clipboard = useClipboard() const clipboard = useClipboard()
const [menuOpen, setMenuOpen] = useState(false)
const { t } = useTranslation() const { t } = useTranslation()
// OneDrive generates thumbnails for its video files, we pick the thumbnail with the highest resolution // OneDrive generates thumbnails for its video files, we pick the thumbnail with the highest resolution
@@ -39,6 +42,7 @@ const VideoPreview: React.FC<{ file: OdFileObject }> = ({ file }) => {
return ( return (
<> <>
<CustomEmbedLinkMenu path={getReadablePath(asPath)} menuOpen={menuOpen} setMenuOpen={setMenuOpen} />
<PreviewContainer> <PreviewContainer>
{error ? ( {error ? (
<FourOhFour errorMsg={error.message} /> <FourOhFour errorMsg={error.message} />
@@ -96,6 +100,12 @@ const VideoPreview: React.FC<{ file: OdFileObject }> = ({ file }) => {
btnText={t('Copy direct link')} btnText={t('Copy direct link')}
btnIcon="copy" btnIcon="copy"
/> />
<DownloadButton
onClickCallback={() => setMenuOpen(true)}
btnColor="teal"
btnText={t('Customise link')}
btnIcon="pen"
/>
<DownloadButton <DownloadButton
onClickCallback={() => window.open(`iina://weblink?url=${file['@microsoft.graph.downloadUrl']}`)} onClickCallback={() => window.open(`iina://weblink?url=${file['@microsoft.graph.downloadUrl']}`)}
+2
View File
@@ -25,6 +25,7 @@ import {
} from '@fortawesome/free-regular-svg-icons' } from '@fortawesome/free-regular-svg-icons'
import { import {
faSearch, faSearch,
faPen,
faCheck, faCheck,
faPlus, faPlus,
faMinus, faMinus,
@@ -109,6 +110,7 @@ library.add(
faThLarge, faThLarge,
faThList, faThList,
faLanguage, faLanguage,
faPen,
...iconList ...iconList
) )
+9
View File
@@ -14,18 +14,25 @@
"Authorisation is required as no valid <2>access_token</2> or <5>refresh_token</5> is present on this deployed instance. Check the following configurations before proceeding with authorising onedrive-vercel-index with your own Microsoft account.": "Authorisation is required as no valid <2>access_token</2> or <5>refresh_token</5> is present on this deployed instance. Check the following configurations before proceeding with authorising onedrive-vercel-index with your own Microsoft account.", "Authorisation is required as no valid <2>access_token</2> or <5>refresh_token</5> is present on this deployed instance. Check the following configurations before proceeding with authorising onedrive-vercel-index with your own Microsoft account.": "Authorisation is required as no valid <2>access_token</2> or <5>refresh_token</5> is present on this deployed instance. Check the following configurations before proceeding with authorising onedrive-vercel-index with your own Microsoft account.",
"Cancel": "Cancel", "Cancel": "Cancel",
"Cannot preview {{path}}": "Cannot preview {{path}}", "Cannot preview {{path}}": "Cannot preview {{path}}",
"Change the raw file direct link to a URL ending with the extension of the file.": "Change the raw file direct link to a URL ending with the extension of the file.",
"Check out <2>Microsoft's official explanation</2> on the error message.": "Check out <2>Microsoft's official explanation</2> on the error message.", "Check out <2>Microsoft's official explanation</2> on the error message.": "Check out <2>Microsoft's official explanation</2> on the error message.",
"Clear all": "Clear all", "Clear all": "Clear all",
"Clear all tokens?": "Clear all tokens?", "Clear all tokens?": "Clear all tokens?",
"Cleared all tokens": "Cleared all tokens", "Cleared all tokens": "Cleared all tokens",
"clearing them means that you will need to re-enter the passwords again.": "clearing them means that you will need to re-enter the passwords again.", "clearing them means that you will need to re-enter the passwords again.": "clearing them means that you will need to re-enter the passwords again.",
"Copied customised link to clipboard.": "Copied customised link to clipboard.",
"Copied direct link to clipboard.": "Copied direct link to clipboard.", "Copied direct link to clipboard.": "Copied direct link to clipboard.",
"Copied folder permalink.": "Copied folder permalink.", "Copied folder permalink.": "Copied folder permalink.",
"Copied raw file permalink.": "Copied raw file permalink.", "Copied raw file permalink.": "Copied raw file permalink.",
"Copy custom link to clipboard": "Copy custom link to clipboard",
"Copy direct link": "Copy direct link", "Copy direct link": "Copy direct link",
"Copy folder permalink": "Copy folder permalink", "Copy folder permalink": "Copy folder permalink",
"Copy raw file permalink": "Copy raw file permalink", "Copy raw file permalink": "Copy raw file permalink",
"Copy the permalink to the file to the clipboard": "Copy the permalink to the file to the clipboard", "Copy the permalink to the file to the clipboard": "Copy the permalink to the file to the clipboard",
"Customise direct link": "Customise direct link",
"Customise link": "Customise link",
"Customised": "Customised",
"Default": "Default",
"Do not pretend to be the site owner": "Do not pretend to be the site owner", "Do not pretend to be the site owner": "Do not pretend to be the site owner",
"Don't worry, after storing them, onedrive-vercel-index will take care of token refreshes and updates after your site goes live.": "Don't worry, after storing them, onedrive-vercel-index will take care of token refreshes and updates after your site goes live.", "Don't worry, after storing them, onedrive-vercel-index will take care of token refreshes and updates after your site goes live.": "Don't worry, after storing them, onedrive-vercel-index will take care of token refreshes and updates after your site goes live.",
"Download": "Download", "Download": "Download",
@@ -47,6 +54,7 @@
"Failed to download selected files.": "Failed to download selected files.", "Failed to download selected files.": "Failed to download selected files.",
"File is empty.": "File is empty.", "File is empty.": "File is empty.",
"File size": "File size", "File size": "File size",
"Filename": "Filename",
"Final step, click the button below to store these tokens persistently before they expire after {{minutes}} minutes {{seconds}} seconds. ": "Final step, click the button below to store these tokens persistently before they expire after {{minutes}} minutes {{seconds}} seconds. ", "Final step, click the button below to store these tokens persistently before they expire after {{minutes}} minutes {{seconds}} seconds. ": "Final step, click the button below to store these tokens persistently before they expire after {{minutes}} minutes {{seconds}} seconds. ",
"Finished downloading folder.": "Finished downloading folder.", "Finished downloading folder.": "Finished downloading folder.",
"Finished downloading selected files.": "Finished downloading selected files.", "Finished downloading selected files.": "Finished downloading selected files.",
@@ -106,6 +114,7 @@
"Waiting for code...": "Waiting for code...", "Waiting for code...": "Waiting for code...",
"Weibo": "Weibo", "Weibo": "Weibo",
"Welcome to your new onedrive-vercel-index 🎉": "Welcome to your new onedrive-vercel-index 🎉", "Welcome to your new onedrive-vercel-index 🎉": "Welcome to your new onedrive-vercel-index 🎉",
"What is this?": "What is this?",
"Where is the auth code? Did you follow step 2 you silly donut?": "Where is the auth code? Did you follow step 2 you silly donut?", "Where is the auth code? Did you follow step 2 you silly donut?": "Where is the auth code? Did you follow step 2 you silly donut?",
"Whoops, looks like we got a problem: {{error}}.": "Whoops, looks like we got a problem: {{error}}." "Whoops, looks like we got a problem: {{error}}.": "Whoops, looks like we got a problem: {{error}}."
} }
+9
View File
@@ -12,18 +12,25 @@
"Authorisation is required as no valid <2>access_token</2> or <5>refresh_token</5> is present on this deployed instance. Check the following configurations before proceeding with authorising onedrive-vercel-index with your own Microsoft account.": "本项目还没有设置有效的 <2>access_token</2> 和 <5>refresh_token</5>,需要进行授权。在继续对 onedrive-vercel-index 授权你的 Microsoft 帐号前,请检查一下下方的配置信息。", "Authorisation is required as no valid <2>access_token</2> or <5>refresh_token</5> is present on this deployed instance. Check the following configurations before proceeding with authorising onedrive-vercel-index with your own Microsoft account.": "本项目还没有设置有效的 <2>access_token</2> 和 <5>refresh_token</5>,需要进行授权。在继续对 onedrive-vercel-index 授权你的 Microsoft 帐号前,请检查一下下方的配置信息。",
"Cancel": "取消", "Cancel": "取消",
"Cannot preview {{path}}": "无法预览 {{path}}", "Cannot preview {{path}}": "无法预览 {{path}}",
"Change the raw file direct link to a URL ending with the extension of the file.": "将文件直链接更改为以文件扩展名结尾的 URL。",
"Check out <2>Microsoft's official explanation</2> on the error message.": "请查阅 <2>Microsoft 官方解释</2> 以获取详细的错误信息。", "Check out <2>Microsoft's official explanation</2> on the error message.": "请查阅 <2>Microsoft 官方解释</2> 以获取详细的错误信息。",
"Clear all": "清除所有密钥", "Clear all": "清除所有密钥",
"Clear all tokens?": "清除所有密钥?", "Clear all tokens?": "清除所有密钥?",
"Cleared all tokens": "已清除所有密钥", "Cleared all tokens": "已清除所有密钥",
"clearing them means that you will need to re-enter the passwords again.": "清除它们意味着下次访问时你需要重新输入密钥。", "clearing them means that you will need to re-enter the passwords again.": "清除它们意味着下次访问时你需要重新输入密钥。",
"Copied customised link to clipboard.": "已复制自定义直链到剪贴板。",
"Copied direct link to clipboard.": "已复制直链到剪贴板。", "Copied direct link to clipboard.": "已复制直链到剪贴板。",
"Copied folder permalink.": "已复制文件夹永久链接。", "Copied folder permalink.": "已复制文件夹永久链接。",
"Copied raw file permalink.": "已复制文件永久链接。", "Copied raw file permalink.": "已复制文件永久链接。",
"Copy custom link to clipboard": "复制自定义链接",
"Copy direct link": "复制文件直链", "Copy direct link": "复制文件直链",
"Copy folder permalink": "复制文件夹永久链接", "Copy folder permalink": "复制文件夹永久链接",
"Copy raw file permalink": "复制文件永久链接", "Copy raw file permalink": "复制文件永久链接",
"Copy the permalink to the file to the clipboard": "复制文件永久链接到剪贴板", "Copy the permalink to the file to the clipboard": "复制文件永久链接到剪贴板",
"Customise direct link": "自定义文件直链",
"Customise link": "自定义直链",
"Customised": "自定义链接",
"Default": "默认",
"Do not pretend to be the site owner": "你不是网站所有者", "Do not pretend to be the site owner": "你不是网站所有者",
"Don't worry, after storing them, onedrive-vercel-index will take care of token refreshes and updates after your site goes live.": "别担心,存储它们之后,onedrive-vercel-index 会在帮助你定时更新 token", "Don't worry, after storing them, onedrive-vercel-index will take care of token refreshes and updates after your site goes live.": "别担心,存储它们之后,onedrive-vercel-index 会在帮助你定时更新 token",
"Download": "下载", "Download": "下载",
@@ -45,6 +52,7 @@
"Failed to download selected files.": "下载选定文件失败。", "Failed to download selected files.": "下载选定文件失败。",
"File is empty.": "文件为空。", "File is empty.": "文件为空。",
"File size": "文件大小", "File size": "文件大小",
"Filename": "文件名",
"Final step, click the button below to store these tokens persistently before they expire after {{minutes}} minutes {{seconds}} seconds. ": "最后一步,在这些 tokens 于 {{minutes}} 分钟 {{seconds}} 秒后失效前,点击下方按钮以永久存储这些 tokens", "Final step, click the button below to store these tokens persistently before they expire after {{minutes}} minutes {{seconds}} seconds. ": "最后一步,在这些 tokens 于 {{minutes}} 分钟 {{seconds}} 秒后失效前,点击下方按钮以永久存储这些 tokens",
"Finished downloading folder.": "下载文件夹成功。", "Finished downloading folder.": "下载文件夹成功。",
"Finished downloading selected files.": "下载选定文件成功。", "Finished downloading selected files.": "下载选定文件成功。",
@@ -102,6 +110,7 @@
"Waiting for code...": "等待授权码…", "Waiting for code...": "等待授权码…",
"Weibo": "微博", "Weibo": "微博",
"Welcome to your new onedrive-vercel-index 🎉": "欢迎来到你崭新的 onedrive-vercel-index 🎉", "Welcome to your new onedrive-vercel-index 🎉": "欢迎来到你崭新的 onedrive-vercel-index 🎉",
"What is this?": "这是什么?",
"Where is the auth code? Did you follow step 2 you silly donut?": "授权码呢?你遵守了第 2 步吗?你这个傻瓜甜甜圈!o( ̄ヘ ̄o#)", "Where is the auth code? Did you follow step 2 you silly donut?": "授权码呢?你遵守了第 2 步吗?你这个傻瓜甜甜圈!o( ̄ヘ ̄o#)",
"Whoops, looks like we got a problem: {{error}}.": "Whoops,看来我们遇到了一个问题:{{error}}" "Whoops, looks like we got a problem: {{error}}.": "Whoops,看来我们遇到了一个问题:{{error}}"
} }