Merge pull request #835 from spencerwooo/swo/housekeeping

This commit is contained in:
Spencer (Shangbo Wu) 2023-01-26 14:47:15 +08:00 committed by GitHub
commit b194a2c07d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 1296 additions and 667 deletions

View file

@ -1,7 +1,7 @@
<div align="center">
<img src="./public/header.png" alt="onedrive-vercel-index" />
<h3><a href="https://drive.swo.moe">onedrive-vercel-index</a></h3>
<p><a href="https://ovi.swo.moe/docs/getting-started">Get started</a> · <a href="https://ovi.swo.moe/blog/whats-new">What's new?</a> · <a href="https://ovi.swo.moe/sponsor">Sponsoring</a></p>
<p><a href="https://ovi.swo.moe/docs/getting-started">Get started</a> · <a href="https://ovi.swo.moe/blog/whats-new">What's new?</a> · <a href="https://ovi.swo.moe/sponsor/ways">Sponsoring</a></p>
<p><em>OneDrive public directory listing, powered by Vercel and Next.js</em></p>
<img src="https://img.shields.io/badge/OneDrive-2C68C3?style=flat&logo=microsoft-onedrive&logoColor=white" alt="OneDrive" />
@ -32,7 +32,7 @@ Please go to our [discussion forum](https://github.com/spencerwooo/onedrive-verc
*If you happen to like this project, please give it a star!* :3
*If you really, really like this project, please send money! -> [Sponsors 🤑 and donations 💰](https://ovi.swo.moe/sponsor)*
*If you really, really like this project, please send money! -> [Sponsors 🤑 and donations 💰](https://ovi.swo.moe/sponsor/ways)*
## Demo
@ -134,11 +134,7 @@ Yes! Completely free with no backend server what-so-ever. (Well, we use Redis, b
Open-source is hard! If you happen to like this project and want me to keep going, please consider sponsoring me or providing a single donation! Thanks for all the love and support!
[🧸 Please donate - 微信/支付宝](https://ovi.swo.moe/sponsor) · [Patreon](https://www.patreon.com/spencerwoo) · [爱发电](https://afdian.net/@spencerwoo)
### Sponsors
*Your name will appear here if you sponsor or donate 😀*
[🧸 Please donate - 微信/支付宝](https://ovi.swo.moe/sponsor/ways) · [Patreon](https://www.patreon.com/spencerwoo) · [爱发电](https://afdian.net/@spencerwoo)
## License

View file

@ -8,11 +8,9 @@ const HomeCrumb = () => {
const { t } = useTranslation()
return (
<Link href="/">
<a className="flex items-center">
<FontAwesomeIcon className="h-3 w-3" icon={['far', 'flag']} />
<span className="ml-2 font-medium">{t('Home')}</span>
</a>
<Link href="/" className="flex items-center">
<FontAwesomeIcon className="h-3 w-3" icon={['far', 'flag']} />
<span className="ml-2 font-medium">{t('Home')}</span>
</Link>
)
}
@ -37,14 +35,11 @@ const Breadcrumb: React.FC<{ query?: ParsedUrlQuery }> = ({ query }) => {
.map(p => encodeURIComponent(p))
.join('/')}`}
passHref
className={`ml-1 transition-all duration-75 hover:opacity-70 md:ml-3 ${
i == 0 && 'pointer-events-none opacity-80'
}`}
>
<a
className={`ml-1 transition-all duration-75 hover:opacity-70 md:ml-3 ${
i == 0 && 'pointer-events-none opacity-80'
}`}
>
{p}
</a>
{p}
</Link>
</li>
))}

View file

@ -370,7 +370,7 @@ const FileListing: FC<{ query?: ParsedUrlQuery }> = ({ query }) => {
{readmeFile && (
<div className="mt-4">
<MarkdownPreview file={readmeFile} path={path} standalone={false} proxy={true} />
<MarkdownPreview file={readmeFile} path={path} standalone={false} />
</div>
)}
</>

View file

@ -176,9 +176,7 @@ const FolderGridLayout = ({
</div>
<Link href={getItemPath(c.name)} passHref>
<a>
<GridItem c={c} path={getItemPath(c.name)} />
</a>
<GridItem c={c} path={getItemPath(c.name)} />
</Link>
</div>
))}

View file

@ -96,10 +96,12 @@ const FolderListLayout = ({
className="grid grid-cols-12 transition-all duration-100 hover:bg-gray-100 dark:hover:bg-gray-850"
key={c.id}
>
<Link href={`${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`} passHref>
<a className="col-span-12 md:col-span-10">
<FileListItem fileContent={c} />
</a>
<Link
href={`${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`}
passHref
className="col-span-12 md:col-span-10"
>
<FileListItem fileContent={c} />
</Link>
{c.folder ? (

View file

@ -188,10 +188,10 @@ export async function* traverseFolder(path: string): AsyncGenerator<TraverseItem
return {
i,
path,
data: await fetcher(
data: await fetcher([
next ? `/api/?path=${path}&next=${next}` : `/api?path=${path}`,
hashedToken ?? undefined
).catch(error => ({ i, path, error })),
hashedToken ?? undefined,
]).catch(error => ({ i, path, error })),
}
}

View file

@ -25,7 +25,7 @@ const Navbar = () => {
const [searchOpen, setSearchOpen] = useState(false)
const openSearchBox = () => setSearchOpen(true)
useHotkeys(`${os === 'mac' ? 'cmd' : 'ctrl'}+k`, e => {
useHotkeys(`${os === 'mac' ? 'meta' : 'ctrl'}+k`, e => {
openSearchBox()
e.preventDefault()
})
@ -64,11 +64,9 @@ const Navbar = () => {
<SearchModal searchOpen={searchOpen} setSearchOpen={setSearchOpen} />
<div className="mx-auto flex w-full items-center justify-between space-x-4 px-4 py-1">
<Link href="/" passHref>
<a className="flex items-center space-x-2 py-2 hover:opacity-80 dark:text-white md:p-2">
<Image src={siteConfig.icon} alt="icon" width="25" height="25" priority />
<span className="hidden font-bold sm:block">{siteConfig.title}</span>
</a>
<Link href="/" passHref className="flex items-center space-x-2 py-2 hover:opacity-80 dark:text-white md:p-2">
<Image src={siteConfig.icon} alt="icon" width="25" height="25" priority />
<span className="hidden font-bold sm:block">{siteConfig.title}</span>
</Link>
<div className="flex flex-1 items-center space-x-4 text-gray-700 md:flex-initial">

View file

@ -90,31 +90,31 @@ function SearchResultItemTemplate({
disabled: boolean
}) {
return (
<Link href={driveItemPath} passHref>
<a
className={`flex items-center space-x-4 border-b border-gray-400/30 px-4 py-1.5 hover:bg-gray-50 dark:hover:bg-gray-850 ${
disabled ? 'pointer-events-none cursor-not-allowed' : 'cursor-pointer'
}`}
>
<FontAwesomeIcon icon={driveItem.file ? getFileIcon(driveItem.name) : ['far', 'folder']} />
<div>
<div className="text-sm font-medium leading-8">{driveItem.name}</div>
<div
className={`overflow-hidden truncate font-mono text-xs opacity-60 ${
itemDescription === 'Loading ...' && 'animate-pulse'
}`}
>
{itemDescription}
</div>
<Link
href={driveItemPath}
passHref
className={`flex items-center space-x-4 border-b border-gray-400/30 px-4 py-1.5 hover:bg-gray-50 dark:hover:bg-gray-850 ${
disabled ? 'pointer-events-none cursor-not-allowed' : 'cursor-pointer'
}`}
>
<FontAwesomeIcon icon={driveItem.file ? getFileIcon(driveItem.name) : ['far', 'folder']} />
<div>
<div className="text-sm font-medium leading-8">{driveItem.name}</div>
<div
className={`overflow-hidden truncate font-mono text-xs opacity-60 ${
itemDescription === 'Loading ...' && 'animate-pulse'
}`}
>
{itemDescription}
</div>
</a>
</div>
</Link>
)
}
function SearchResultItemLoadRemote({ result }: { result: OdSearchResult[number] }) {
const { data, error }: SWRResponse<OdDriveItem, { status: number; message: any }> = useSWR(
`/api/item/?id=${result.id}`,
[`/api/item/?id=${result.id}`],
fetcher
)

View file

@ -9,8 +9,8 @@ import { useCookies, withCookies } from 'react-cookie'
// https://headlessui.dev/react/menu#integrating-with-next-js
const CustomLink = ({ href, children, as, locale, ...props }): JSX.Element => {
return (
<Link href={href} as={as} locale={locale}>
<a {...props}>{children}</a>
<Link href={href} as={as} locale={locale} {...props}>
{children}
</Link>
)
}

View file

@ -62,7 +62,7 @@ const EPUBPreview: FC<{ file: OdFileObject }> = ({ file }) => {
location={location}
locationChanged={onLocationChange}
epubInitOptions={{ openAs: 'epub' }}
epubOptions={{ flow: 'scrolled' }}
epubOptions={{ flow: 'scrolled', allowPopups: true }}
/>
</div>
</div>

View file

@ -20,16 +20,11 @@ const MarkdownPreview: FC<{
file: any
path: string
standalone?: boolean
proxy?: boolean
}> = ({ file, path, standalone = true, proxy = false }) => {
}> = ({ file, path, standalone = true }) => {
// The parent folder of the markdown file, which is also the relative image folder
const parentPath = standalone ? path.substring(0, path.lastIndexOf('/')) : path
const {
response: content,
error,
validating,
} = useFileContent(`/api/raw/?path=${parentPath}/${file.name}${proxy ? `&proxy=true` : ''}`, path)
const { response: content, error, validating } = useFileContent(`/api/raw/?path=${parentPath}/${file.name}`, path)
const { t } = useTranslation()
// Check if the image is relative path instead of a absolute url

9
i18next.d.ts vendored Normal file
View file

@ -0,0 +1,9 @@
import 'i18next'
declare module 'i18next' {
interface CustomTypeOptions {
// This is set to prevent i18next's t function to return null
// https://github.com/i18next/next-i18next/issues/2038
returnNull: false
}
}

View file

@ -11,27 +11,28 @@
"extract": "i18next"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.35",
"@fortawesome/free-brands-svg-icons": "^5.15.4",
"@fortawesome/free-regular-svg-icons": "^5.15.3",
"@fortawesome/free-solid-svg-icons": "^5.15.3",
"@fortawesome/react-fontawesome": "^0.1.14",
"@headlessui/react": "^1.7.3",
"@fortawesome/fontawesome-svg-core": "^6.2.1",
"@fortawesome/free-brands-svg-icons": "^6.2.1",
"@fortawesome/free-regular-svg-icons": "^6.2.1",
"@fortawesome/free-solid-svg-icons": "^6.2.1",
"@fortawesome/react-fontawesome": "^0.2.0",
"@headlessui/react": "^1.7.7",
"@tailwindcss/line-clamp": "^0.4.2",
"awesome-debounce-promise": "^2.1.0",
"axios": "^1.1.2",
"axios": "^1.2.4",
"cors": "^2.8.5",
"crypto-js": "^4.1.1",
"csstype": "^3.1.1",
"dayjs": "^1.11.5",
"dayjs": "^1.11.7",
"emoji-regex": "^10.2.1",
"ioredis": "^5.2.3",
"i18next": "^22.4.9",
"ioredis": "^5.3.0",
"jszip": "^3.10.1",
"mpegts.js": "^1.6.10",
"next": "^12.3.1",
"next-i18next": "^12.1.0",
"nextjs-progressbar": "^0.0.14",
"plyr-react": "^5.1.0",
"mpegts.js": "^1.7.2",
"next": "^13.1.5",
"next-i18next": "^13.0.3",
"nextjs-progressbar": "^0.0.16",
"plyr-react": "^5.1.2",
"preview-office-docs": "^1.0.2",
"react": "^18.2.0",
"react-async-hook": "^4.0.0",
@ -40,37 +41,38 @@
"react-copy-to-clipboard": "^5.0.3",
"react-dom": "^18.2.0",
"react-hot-toast": "^2.4.0",
"react-hotkeys-hook": "^3.4.7",
"react-markdown": "^8.0.3",
"react-reader": "^0.21.3",
"react-hotkeys-hook": "^4.3.2",
"react-i18next": "^12.1.4",
"react-markdown": "^8.0.5",
"react-reader": "^1.0.2",
"react-syntax-highlighter": "^15.5.0",
"react-use-system-theme": "^1.1.1",
"rehype-katex": "^6.0.2",
"rehype-raw": "^6.0.0",
"remark-gfm": "^3.0.1",
"remark-math": "^5.1.1",
"swr": "^1.3.0",
"swr": "^2.0.1",
"use-clipboard-copy": "^0.2.0",
"use-constant": "^1.1.1"
},
"devDependencies": {
"@types/cors": "^2.8.12",
"@types/cors": "^2.8.13",
"@types/crypto-js": "^4.0.2",
"@types/node": "18.8.3",
"@types/react": "18.0.21",
"@types/node": "18.11.18",
"@types/react": "18.0.27",
"@types/react-copy-to-clipboard": "^5.0.4",
"@types/react-dom": "^18.0.6",
"@types/react-pdf": "^5.0.4",
"@types/react-syntax-highlighter": "^15.5.5",
"autoprefixer": "^10.4.12",
"eslint": "8.25.0",
"eslint-config-next": "12.3.1",
"eslint-config-prettier": "^8.5.0",
"i18next-parser": "^6.6.0",
"postcss": "^8.4.17",
"prettier": "^2.7.1",
"prettier-plugin-tailwindcss": "^0.1.13",
"tailwindcss": "^3.1.8",
"typescript": "4.8.4"
"@types/react-dom": "^18.0.10",
"@types/react-pdf": "^6.2.0",
"@types/react-syntax-highlighter": "^15.5.6",
"autoprefixer": "^10.4.13",
"eslint": "8.32.0",
"eslint-config-next": "13.1.5",
"eslint-config-prettier": "^8.6.0",
"i18next-parser": "^7.6.0",
"postcss": "^8.4.21",
"prettier": "^2.8.3",
"prettier-plugin-tailwindcss": "^0.2.2",
"tailwindcss": "^3.2.4",
"typescript": "4.9.4"
}
}

View file

@ -1,12 +1,13 @@
import { config } from '@fortawesome/fontawesome-svg-core'
import '@fortawesome/fontawesome-svg-core/styles.css'
import '../styles/globals.css'
import '../styles/markdown-github.css'
// Require had to be used to prevent SSR failure in Next.js
// Related discussion: https://github.com/FortAwesome/Font-Awesome/issues/19348
const { library, config } = require('@fortawesome/fontawesome-svg-core')
config.autoAddCss = false
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faFileImage,
faFilePdf,

View file

@ -9,7 +9,7 @@ class MyDocument extends Document {
<meta name="description" content="OneDrive Vercel Index" />
<link rel="icon" href="/favicon.ico" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="true" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="" />
{siteConfig.googleFontLinks.map(link => (
<link key={link} rel="stylesheet" href={link} />
))}

View file

@ -1,7 +1,7 @@
import { posix as pathPosix } from 'path'
import type { NextApiRequest, NextApiResponse } from 'next'
import axios from 'axios'
import axios, { AxiosResponseHeaders } from 'axios'
import Cors from 'cors'
import { driveApi, cacheControlHeader } from '../../config/api.config'
@ -77,7 +77,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
})
headers['Cache-Control'] = cacheControlHeader
// Send data stream as response
res.writeHead(200, headers)
res.writeHead(200, headers as AxiosResponseHeaders)
stream.pipe(res)
} else {
res.redirect(data['@microsoft.graph.downloadUrl'])

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,7 @@ import type { OdAPIResponse } from '../types'
import { getStoredToken } from './protectedRouteHandler'
// Common axios fetch function for use with useSWR
export async function fetcher(url: string, token?: string): Promise<any> {
export async function fetcher([url, token]: [url: string, token?: string]): Promise<any> {
try {
return (
await (token

View file

@ -97,11 +97,13 @@ const extensions = {
* To stop TypeScript complaining about indexing the object with a non-existent key
* https://dev.to/mapleleaf/indexing-objects-in-typescript-1cgi
*
* Fixed by ChatGPT with the upgrade of TypeScript 4.9
*
* @param obj Object with keys to index
* @param key The index key
* @returns Whether or not the key exists inside the object
*/
export function hasKey<O>(obj: O, key: PropertyKey): key is keyof O {
export function hasKey(obj: Record<string, any>, key: string): boolean {
return key in obj
}