Merge pull request #371 from myl7/readable-path

This commit is contained in:
Spencer Woo
2022-02-08 16:32:27 +08:00
committed by GitHub
5 changed files with 63 additions and 8 deletions
+3 -2
View File
@@ -8,6 +8,7 @@ import Image from 'next/image'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { getBaseUrl } from '../utils/getBaseUrl' import { getBaseUrl } from '../utils/getBaseUrl'
import { getReadablePath } from '../utils/getReadablePath'
const btnStyleMap = (btnColor?: string) => { const btnStyleMap = (btnColor?: string) => {
const colorMap = { const colorMap = {
@@ -46,7 +47,7 @@ export const DownloadButton = ({
}) => { }) => {
return ( return (
<button <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( className={`flex items-center space-x-2 rounded-lg border bg-white py-2 px-4 text-sm font-medium text-gray-900 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 btnColor
)}`} )}`}
title={btnTitle} title={btnTitle}
@@ -81,7 +82,7 @@ const DownloadButtonGroup: React.FC<{ downloadUrl: string }> = ({ downloadUrl })
/> */} /> */}
<DownloadButton <DownloadButton
onClickCallback={() => { onClickCallback={() => {
clipboard.copy(`${getBaseUrl()}/api?path=${asPath}&raw=true`) clipboard.copy(`${getBaseUrl()}/api?path=${getReadablePath(asPath)}&raw=true`)
toast.success('Copied direct link to clipboard.') toast.success('Copied direct link to clipboard.')
}} }}
btnColor="pink" btnColor="pink"
+7 -2
View File
@@ -7,6 +7,7 @@ import { useClipboard } from 'use-clipboard-copy'
import { getBaseUrl } from '../utils/getBaseUrl' import { getBaseUrl } from '../utils/getBaseUrl'
import { formatModifiedDateTime } from '../utils/fileDetails' import { formatModifiedDateTime } from '../utils/fileDetails'
import { getReadablePath } from '../utils/getReadablePath'
import { Checkbox, ChildIcon, Downloading, formatChildName } from './FileListing' import { Checkbox, ChildIcon, Downloading, formatChildName } from './FileListing'
const GridItem = ({ c }: { c: OdFolderChildren }) => { const GridItem = ({ c }: { c: OdFolderChildren }) => {
@@ -104,7 +105,9 @@ const FolderGridLayout = ({
title="Copy folder permalink" title="Copy folder permalink"
className="cursor-pointer rounded px-1.5 py-1 hover:bg-gray-300 dark:hover:bg-gray-600" className="cursor-pointer rounded px-1.5 py-1 hover:bg-gray-300 dark:hover:bg-gray-600"
onClick={() => { onClick={() => {
clipboard.copy(`${getBaseUrl()}${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`) clipboard.copy(
`${getBaseUrl()}${getReadablePath(`${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`)}`
)
toast('Copied folder permalink.', { icon: '👌' }) toast('Copied folder permalink.', { icon: '👌' })
}} }}
> >
@@ -132,7 +135,9 @@ const FolderGridLayout = ({
className="cursor-pointer rounded px-1.5 py-1 hover:bg-gray-300 dark:hover:bg-gray-600" className="cursor-pointer rounded px-1.5 py-1 hover:bg-gray-300 dark:hover:bg-gray-600"
onClick={() => { onClick={() => {
clipboard.copy( clipboard.copy(
`${getBaseUrl()}/api?path=${path === '/' ? '' : path}/${encodeURIComponent(c.name)}&raw=true` `${getBaseUrl()}/api?path=${getReadablePath(
`${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`
)}&raw=true`
) )
toast.success('Copied raw file permalink.') toast.success('Copied raw file permalink.')
}} }}
+7 -2
View File
@@ -7,6 +7,7 @@ import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import { getBaseUrl } from '../utils/getBaseUrl' import { getBaseUrl } from '../utils/getBaseUrl'
import { humanFileSize, formatModifiedDateTime } from '../utils/fileDetails' import { humanFileSize, formatModifiedDateTime } from '../utils/fileDetails'
import { getReadablePath } from '../utils/getReadablePath'
import { Downloading, Checkbox, formatChildName, ChildIcon } from './FileListing' import { Downloading, Checkbox, formatChildName, ChildIcon } from './FileListing'
@@ -100,7 +101,9 @@ const FolderListLayout = ({
title="Copy folder permalink" title="Copy folder permalink"
className="cursor-pointer rounded px-1.5 py-1 hover:bg-gray-300 dark:hover:bg-gray-600" className="cursor-pointer rounded px-1.5 py-1 hover:bg-gray-300 dark:hover:bg-gray-600"
onClick={() => { onClick={() => {
clipboard.copy(`${getBaseUrl()}${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`) clipboard.copy(
`${getBaseUrl()}${getReadablePath(`${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`)}`
)
toast('Copied folder permalink.', { icon: '👌' }) toast('Copied folder permalink.', { icon: '👌' })
}} }}
> >
@@ -128,7 +131,9 @@ const FolderListLayout = ({
className="cursor-pointer rounded px-1.5 py-1 hover:bg-gray-300 dark:hover:bg-gray-600" className="cursor-pointer rounded px-1.5 py-1 hover:bg-gray-300 dark:hover:bg-gray-600"
onClick={() => { onClick={() => {
clipboard.copy( clipboard.copy(
`${getBaseUrl()}/api?path=${path === '/' ? '' : path}/${encodeURIComponent(c.name)}&raw=true` `${getBaseUrl()}/api?path=${getReadablePath(
`${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`
)}&raw=true`
) )
toast.success('Copied raw file permalink.') toast.success('Copied raw file permalink.')
}} }}
+3 -2
View File
@@ -6,9 +6,10 @@ import toast from 'react-hot-toast'
import { useAsync } from 'react-async-hook' import { useAsync } from 'react-async-hook'
import { getBaseUrl } from '../../utils/getBaseUrl' import { getBaseUrl } from '../../utils/getBaseUrl'
import { getExtension } from '../../utils/getFileIcon'
import { getReadablePath } from '../../utils/getReadablePath'
import { DownloadButton } from '../DownloadBtnGtoup' import { DownloadButton } from '../DownloadBtnGtoup'
import { DownloadBtnContainer, PreviewContainer } from './Containers' import { DownloadBtnContainer, PreviewContainer } from './Containers'
import { getExtension } from '../../utils/getFileIcon'
import FourOhFour from '../FourOhFour' import FourOhFour from '../FourOhFour'
import Loading from '../Loading' import Loading from '../Loading'
@@ -85,7 +86,7 @@ const VideoPreview: React.FC<{ file: OdFileObject }> = ({ file }) => {
/> */} /> */}
<DownloadButton <DownloadButton
onClickCallback={() => { onClickCallback={() => {
clipboard.copy(`${getBaseUrl()}/api?path=${asPath}&raw=true`) clipboard.copy(`${getBaseUrl()}/api?path=${getReadablePath(asPath)}&raw=true`)
toast.success('Copied direct link to clipboard.') toast.success('Copied direct link to clipboard.')
}} }}
btnColor="pink" btnColor="pink"
+43
View File
@@ -0,0 +1,43 @@
/**
* Make path readable but still valid in URL (means the whole URL is still recognized as a URL)
* @param path Path. May be used as URL path or query value.
* @returns Readable but still valid path
*/
export function getReadablePath(path: string) {
path = path
.split('/')
.map(s => decodeURIComponent(s))
.map(s =>
Array.from(s)
.map(c => (isSafeChar(c) ? c : encodeURIComponent(c)))
.join('')
)
.join('/')
// Handle trailing char for autolink
// Ref: https://github.github.com/gfm/#autolinks-extension-
if (/^[!,:*]$/.test(path[path.length - 1])) {
path = path.substring(0, path.length - 1) + encodeURIComponent(path[path.length - 1])
}
return path
}
// Check if the character is safe (means no need of percent-encoding)
function isSafeChar(c: string) {
if (c.charCodeAt(0) < 0x80) {
// ASCII
if (/^[a-zA-Z0-9\-._~]$/.test(c)) {
// RFC3986 unreserved chars
return true
} else if (/^[*:+@,!]$/.test(c)) {
// Some extra pretty safe chars for URL path or query
// Ref: https://stackoverflow.com/a/42287988/11691878
return true
}
} else {
if (!/\s|\u180e/.test(c)) {
// Non-whitespace char. \u180e is missed in \s.
return true
}
}
return false
}