Merge pull request #835 from spencerwooo/swo/housekeeping
This commit is contained in:
commit
b194a2c07d
19 changed files with 1296 additions and 667 deletions
10
README.md
10
README.md
|
@ -1,7 +1,7 @@
|
||||||
<div align="center">
|
<div align="center">
|
||||||
<img src="./public/header.png" alt="onedrive-vercel-index" />
|
<img src="./public/header.png" alt="onedrive-vercel-index" />
|
||||||
<h3><a href="https://drive.swo.moe">onedrive-vercel-index</a></h3>
|
<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>
|
<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" />
|
<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 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
|
## 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!
|
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)
|
[🧸 Please donate - 微信/支付宝](https://ovi.swo.moe/sponsor/ways) · [Patreon](https://www.patreon.com/spencerwoo) · [爱发电](https://afdian.net/@spencerwoo)
|
||||||
|
|
||||||
### Sponsors
|
|
||||||
|
|
||||||
*Your name will appear here if you sponsor or donate 😀*
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,9 @@ const HomeCrumb = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href="/">
|
<Link href="/" className="flex items-center">
|
||||||
<a className="flex items-center">
|
<FontAwesomeIcon className="h-3 w-3" icon={['far', 'flag']} />
|
||||||
<FontAwesomeIcon className="h-3 w-3" icon={['far', 'flag']} />
|
<span className="ml-2 font-medium">{t('Home')}</span>
|
||||||
<span className="ml-2 font-medium">{t('Home')}</span>
|
|
||||||
</a>
|
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -37,14 +35,11 @@ const Breadcrumb: React.FC<{ query?: ParsedUrlQuery }> = ({ query }) => {
|
||||||
.map(p => encodeURIComponent(p))
|
.map(p => encodeURIComponent(p))
|
||||||
.join('/')}`}
|
.join('/')}`}
|
||||||
passHref
|
passHref
|
||||||
|
className={`ml-1 transition-all duration-75 hover:opacity-70 md:ml-3 ${
|
||||||
|
i == 0 && 'pointer-events-none opacity-80'
|
||||||
|
}`}
|
||||||
>
|
>
|
||||||
<a
|
{p}
|
||||||
className={`ml-1 transition-all duration-75 hover:opacity-70 md:ml-3 ${
|
|
||||||
i == 0 && 'pointer-events-none opacity-80'
|
|
||||||
}`}
|
|
||||||
>
|
|
||||||
{p}
|
|
||||||
</a>
|
|
||||||
</Link>
|
</Link>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -370,7 +370,7 @@ const FileListing: FC<{ query?: ParsedUrlQuery }> = ({ query }) => {
|
||||||
|
|
||||||
{readmeFile && (
|
{readmeFile && (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<MarkdownPreview file={readmeFile} path={path} standalone={false} proxy={true} />
|
<MarkdownPreview file={readmeFile} path={path} standalone={false} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
|
@ -176,9 +176,7 @@ const FolderGridLayout = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Link href={getItemPath(c.name)} passHref>
|
<Link href={getItemPath(c.name)} passHref>
|
||||||
<a>
|
<GridItem c={c} path={getItemPath(c.name)} />
|
||||||
<GridItem c={c} path={getItemPath(c.name)} />
|
|
||||||
</a>
|
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -96,10 +96,12 @@ const FolderListLayout = ({
|
||||||
className="grid grid-cols-12 transition-all duration-100 hover:bg-gray-100 dark:hover:bg-gray-850"
|
className="grid grid-cols-12 transition-all duration-100 hover:bg-gray-100 dark:hover:bg-gray-850"
|
||||||
key={c.id}
|
key={c.id}
|
||||||
>
|
>
|
||||||
<Link href={`${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`} passHref>
|
<Link
|
||||||
<a className="col-span-12 md:col-span-10">
|
href={`${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`}
|
||||||
<FileListItem fileContent={c} />
|
passHref
|
||||||
</a>
|
className="col-span-12 md:col-span-10"
|
||||||
|
>
|
||||||
|
<FileListItem fileContent={c} />
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
{c.folder ? (
|
{c.folder ? (
|
||||||
|
|
|
@ -188,10 +188,10 @@ export async function* traverseFolder(path: string): AsyncGenerator<TraverseItem
|
||||||
return {
|
return {
|
||||||
i,
|
i,
|
||||||
path,
|
path,
|
||||||
data: await fetcher(
|
data: await fetcher([
|
||||||
next ? `/api/?path=${path}&next=${next}` : `/api?path=${path}`,
|
next ? `/api/?path=${path}&next=${next}` : `/api?path=${path}`,
|
||||||
hashedToken ?? undefined
|
hashedToken ?? undefined,
|
||||||
).catch(error => ({ i, path, error })),
|
]).catch(error => ({ i, path, error })),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ const Navbar = () => {
|
||||||
const [searchOpen, setSearchOpen] = useState(false)
|
const [searchOpen, setSearchOpen] = useState(false)
|
||||||
const openSearchBox = () => setSearchOpen(true)
|
const openSearchBox = () => setSearchOpen(true)
|
||||||
|
|
||||||
useHotkeys(`${os === 'mac' ? 'cmd' : 'ctrl'}+k`, e => {
|
useHotkeys(`${os === 'mac' ? 'meta' : 'ctrl'}+k`, e => {
|
||||||
openSearchBox()
|
openSearchBox()
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
})
|
})
|
||||||
|
@ -64,11 +64,9 @@ const Navbar = () => {
|
||||||
<SearchModal searchOpen={searchOpen} setSearchOpen={setSearchOpen} />
|
<SearchModal searchOpen={searchOpen} setSearchOpen={setSearchOpen} />
|
||||||
|
|
||||||
<div className="mx-auto flex w-full items-center justify-between space-x-4 px-4 py-1">
|
<div className="mx-auto flex w-full items-center justify-between space-x-4 px-4 py-1">
|
||||||
<Link href="/" passHref>
|
<Link href="/" passHref className="flex items-center space-x-2 py-2 hover:opacity-80 dark:text-white md:p-2">
|
||||||
<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 />
|
||||||
<Image src={siteConfig.icon} alt="icon" width="25" height="25" priority />
|
<span className="hidden font-bold sm:block">{siteConfig.title}</span>
|
||||||
<span className="hidden font-bold sm:block">{siteConfig.title}</span>
|
|
||||||
</a>
|
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<div className="flex flex-1 items-center space-x-4 text-gray-700 md:flex-initial">
|
<div className="flex flex-1 items-center space-x-4 text-gray-700 md:flex-initial">
|
||||||
|
|
|
@ -90,31 +90,31 @@ function SearchResultItemTemplate({
|
||||||
disabled: boolean
|
disabled: boolean
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Link href={driveItemPath} passHref>
|
<Link
|
||||||
<a
|
href={driveItemPath}
|
||||||
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 ${
|
passHref
|
||||||
disabled ? 'pointer-events-none cursor-not-allowed' : 'cursor-pointer'
|
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>
|
<FontAwesomeIcon icon={driveItem.file ? getFileIcon(driveItem.name) : ['far', 'folder']} />
|
||||||
<div className="text-sm font-medium leading-8">{driveItem.name}</div>
|
<div>
|
||||||
<div
|
<div className="text-sm font-medium leading-8">{driveItem.name}</div>
|
||||||
className={`overflow-hidden truncate font-mono text-xs opacity-60 ${
|
<div
|
||||||
itemDescription === 'Loading ...' && 'animate-pulse'
|
className={`overflow-hidden truncate font-mono text-xs opacity-60 ${
|
||||||
}`}
|
itemDescription === 'Loading ...' && 'animate-pulse'
|
||||||
>
|
}`}
|
||||||
{itemDescription}
|
>
|
||||||
</div>
|
{itemDescription}
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function SearchResultItemLoadRemote({ result }: { result: OdSearchResult[number] }) {
|
function SearchResultItemLoadRemote({ result }: { result: OdSearchResult[number] }) {
|
||||||
const { data, error }: SWRResponse<OdDriveItem, { status: number; message: any }> = useSWR(
|
const { data, error }: SWRResponse<OdDriveItem, { status: number; message: any }> = useSWR(
|
||||||
`/api/item/?id=${result.id}`,
|
[`/api/item/?id=${result.id}`],
|
||||||
fetcher
|
fetcher
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ import { useCookies, withCookies } from 'react-cookie'
|
||||||
// https://headlessui.dev/react/menu#integrating-with-next-js
|
// https://headlessui.dev/react/menu#integrating-with-next-js
|
||||||
const CustomLink = ({ href, children, as, locale, ...props }): JSX.Element => {
|
const CustomLink = ({ href, children, as, locale, ...props }): JSX.Element => {
|
||||||
return (
|
return (
|
||||||
<Link href={href} as={as} locale={locale}>
|
<Link href={href} as={as} locale={locale} {...props}>
|
||||||
<a {...props}>{children}</a>
|
{children}
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ const EPUBPreview: FC<{ file: OdFileObject }> = ({ file }) => {
|
||||||
location={location}
|
location={location}
|
||||||
locationChanged={onLocationChange}
|
locationChanged={onLocationChange}
|
||||||
epubInitOptions={{ openAs: 'epub' }}
|
epubInitOptions={{ openAs: 'epub' }}
|
||||||
epubOptions={{ flow: 'scrolled' }}
|
epubOptions={{ flow: 'scrolled', allowPopups: true }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,16 +20,11 @@ const MarkdownPreview: FC<{
|
||||||
file: any
|
file: any
|
||||||
path: string
|
path: string
|
||||||
standalone?: boolean
|
standalone?: boolean
|
||||||
proxy?: boolean
|
}> = ({ file, path, standalone = true }) => {
|
||||||
}> = ({ file, path, standalone = true, proxy = false }) => {
|
|
||||||
// The parent folder of the markdown file, which is also the relative image folder
|
// The parent folder of the markdown file, which is also the relative image folder
|
||||||
const parentPath = standalone ? path.substring(0, path.lastIndexOf('/')) : path
|
const parentPath = standalone ? path.substring(0, path.lastIndexOf('/')) : path
|
||||||
|
|
||||||
const {
|
const { response: content, error, validating } = useFileContent(`/api/raw/?path=${parentPath}/${file.name}`, path)
|
||||||
response: content,
|
|
||||||
error,
|
|
||||||
validating,
|
|
||||||
} = useFileContent(`/api/raw/?path=${parentPath}/${file.name}${proxy ? `&proxy=true` : ''}`, path)
|
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
||||||
// Check if the image is relative path instead of a absolute url
|
// Check if the image is relative path instead of a absolute url
|
||||||
|
|
9
i18next.d.ts
vendored
Normal file
9
i18next.d.ts
vendored
Normal 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
|
||||||
|
}
|
||||||
|
}
|
70
package.json
70
package.json
|
@ -11,27 +11,28 @@
|
||||||
"extract": "i18next"
|
"extract": "i18next"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "^1.2.35",
|
"@fortawesome/fontawesome-svg-core": "^6.2.1",
|
||||||
"@fortawesome/free-brands-svg-icons": "^5.15.4",
|
"@fortawesome/free-brands-svg-icons": "^6.2.1",
|
||||||
"@fortawesome/free-regular-svg-icons": "^5.15.3",
|
"@fortawesome/free-regular-svg-icons": "^6.2.1",
|
||||||
"@fortawesome/free-solid-svg-icons": "^5.15.3",
|
"@fortawesome/free-solid-svg-icons": "^6.2.1",
|
||||||
"@fortawesome/react-fontawesome": "^0.1.14",
|
"@fortawesome/react-fontawesome": "^0.2.0",
|
||||||
"@headlessui/react": "^1.7.3",
|
"@headlessui/react": "^1.7.7",
|
||||||
"@tailwindcss/line-clamp": "^0.4.2",
|
"@tailwindcss/line-clamp": "^0.4.2",
|
||||||
"awesome-debounce-promise": "^2.1.0",
|
"awesome-debounce-promise": "^2.1.0",
|
||||||
"axios": "^1.1.2",
|
"axios": "^1.2.4",
|
||||||
"cors": "^2.8.5",
|
"cors": "^2.8.5",
|
||||||
"crypto-js": "^4.1.1",
|
"crypto-js": "^4.1.1",
|
||||||
"csstype": "^3.1.1",
|
"csstype": "^3.1.1",
|
||||||
"dayjs": "^1.11.5",
|
"dayjs": "^1.11.7",
|
||||||
"emoji-regex": "^10.2.1",
|
"emoji-regex": "^10.2.1",
|
||||||
"ioredis": "^5.2.3",
|
"i18next": "^22.4.9",
|
||||||
|
"ioredis": "^5.3.0",
|
||||||
"jszip": "^3.10.1",
|
"jszip": "^3.10.1",
|
||||||
"mpegts.js": "^1.6.10",
|
"mpegts.js": "^1.7.2",
|
||||||
"next": "^12.3.1",
|
"next": "^13.1.5",
|
||||||
"next-i18next": "^12.1.0",
|
"next-i18next": "^13.0.3",
|
||||||
"nextjs-progressbar": "^0.0.14",
|
"nextjs-progressbar": "^0.0.16",
|
||||||
"plyr-react": "^5.1.0",
|
"plyr-react": "^5.1.2",
|
||||||
"preview-office-docs": "^1.0.2",
|
"preview-office-docs": "^1.0.2",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-async-hook": "^4.0.0",
|
"react-async-hook": "^4.0.0",
|
||||||
|
@ -40,37 +41,38 @@
|
||||||
"react-copy-to-clipboard": "^5.0.3",
|
"react-copy-to-clipboard": "^5.0.3",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"react-hot-toast": "^2.4.0",
|
"react-hot-toast": "^2.4.0",
|
||||||
"react-hotkeys-hook": "^3.4.7",
|
"react-hotkeys-hook": "^4.3.2",
|
||||||
"react-markdown": "^8.0.3",
|
"react-i18next": "^12.1.4",
|
||||||
"react-reader": "^0.21.3",
|
"react-markdown": "^8.0.5",
|
||||||
|
"react-reader": "^1.0.2",
|
||||||
"react-syntax-highlighter": "^15.5.0",
|
"react-syntax-highlighter": "^15.5.0",
|
||||||
"react-use-system-theme": "^1.1.1",
|
"react-use-system-theme": "^1.1.1",
|
||||||
"rehype-katex": "^6.0.2",
|
"rehype-katex": "^6.0.2",
|
||||||
"rehype-raw": "^6.0.0",
|
"rehype-raw": "^6.0.0",
|
||||||
"remark-gfm": "^3.0.1",
|
"remark-gfm": "^3.0.1",
|
||||||
"remark-math": "^5.1.1",
|
"remark-math": "^5.1.1",
|
||||||
"swr": "^1.3.0",
|
"swr": "^2.0.1",
|
||||||
"use-clipboard-copy": "^0.2.0",
|
"use-clipboard-copy": "^0.2.0",
|
||||||
"use-constant": "^1.1.1"
|
"use-constant": "^1.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/cors": "^2.8.12",
|
"@types/cors": "^2.8.13",
|
||||||
"@types/crypto-js": "^4.0.2",
|
"@types/crypto-js": "^4.0.2",
|
||||||
"@types/node": "18.8.3",
|
"@types/node": "18.11.18",
|
||||||
"@types/react": "18.0.21",
|
"@types/react": "18.0.27",
|
||||||
"@types/react-copy-to-clipboard": "^5.0.4",
|
"@types/react-copy-to-clipboard": "^5.0.4",
|
||||||
"@types/react-dom": "^18.0.6",
|
"@types/react-dom": "^18.0.10",
|
||||||
"@types/react-pdf": "^5.0.4",
|
"@types/react-pdf": "^6.2.0",
|
||||||
"@types/react-syntax-highlighter": "^15.5.5",
|
"@types/react-syntax-highlighter": "^15.5.6",
|
||||||
"autoprefixer": "^10.4.12",
|
"autoprefixer": "^10.4.13",
|
||||||
"eslint": "8.25.0",
|
"eslint": "8.32.0",
|
||||||
"eslint-config-next": "12.3.1",
|
"eslint-config-next": "13.1.5",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.6.0",
|
||||||
"i18next-parser": "^6.6.0",
|
"i18next-parser": "^7.6.0",
|
||||||
"postcss": "^8.4.17",
|
"postcss": "^8.4.21",
|
||||||
"prettier": "^2.7.1",
|
"prettier": "^2.8.3",
|
||||||
"prettier-plugin-tailwindcss": "^0.1.13",
|
"prettier-plugin-tailwindcss": "^0.2.2",
|
||||||
"tailwindcss": "^3.1.8",
|
"tailwindcss": "^3.2.4",
|
||||||
"typescript": "4.8.4"
|
"typescript": "4.9.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
import { config } from '@fortawesome/fontawesome-svg-core'
|
|
||||||
import '@fortawesome/fontawesome-svg-core/styles.css'
|
import '@fortawesome/fontawesome-svg-core/styles.css'
|
||||||
|
|
||||||
import '../styles/globals.css'
|
import '../styles/globals.css'
|
||||||
import '../styles/markdown-github.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
|
config.autoAddCss = false
|
||||||
|
|
||||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
|
||||||
import {
|
import {
|
||||||
faFileImage,
|
faFileImage,
|
||||||
faFilePdf,
|
faFilePdf,
|
||||||
|
|
|
@ -9,7 +9,7 @@ class MyDocument extends Document {
|
||||||
<meta name="description" content="OneDrive Vercel Index" />
|
<meta name="description" content="OneDrive Vercel Index" />
|
||||||
<link rel="icon" href="/favicon.ico" />
|
<link rel="icon" href="/favicon.ico" />
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<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 => (
|
{siteConfig.googleFontLinks.map(link => (
|
||||||
<link key={link} rel="stylesheet" href={link} />
|
<link key={link} rel="stylesheet" href={link} />
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { posix as pathPosix } from 'path'
|
import { posix as pathPosix } from 'path'
|
||||||
|
|
||||||
import type { NextApiRequest, NextApiResponse } from 'next'
|
import type { NextApiRequest, NextApiResponse } from 'next'
|
||||||
import axios from 'axios'
|
import axios, { AxiosResponseHeaders } from 'axios'
|
||||||
import Cors from 'cors'
|
import Cors from 'cors'
|
||||||
|
|
||||||
import { driveApi, cacheControlHeader } from '../../config/api.config'
|
import { driveApi, cacheControlHeader } from '../../config/api.config'
|
||||||
|
@ -77,7 +77,7 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
|
||||||
})
|
})
|
||||||
headers['Cache-Control'] = cacheControlHeader
|
headers['Cache-Control'] = cacheControlHeader
|
||||||
// Send data stream as response
|
// Send data stream as response
|
||||||
res.writeHead(200, headers)
|
res.writeHead(200, headers as AxiosResponseHeaders)
|
||||||
stream.pipe(res)
|
stream.pipe(res)
|
||||||
} else {
|
} else {
|
||||||
res.redirect(data['@microsoft.graph.downloadUrl'])
|
res.redirect(data['@microsoft.graph.downloadUrl'])
|
||||||
|
|
1755
pnpm-lock.yaml
1755
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
@ -6,7 +6,7 @@ import type { OdAPIResponse } from '../types'
|
||||||
import { getStoredToken } from './protectedRouteHandler'
|
import { getStoredToken } from './protectedRouteHandler'
|
||||||
|
|
||||||
// Common axios fetch function for use with useSWR
|
// 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 {
|
try {
|
||||||
return (
|
return (
|
||||||
await (token
|
await (token
|
||||||
|
|
|
@ -97,11 +97,13 @@ const extensions = {
|
||||||
* To stop TypeScript complaining about indexing the object with a non-existent key
|
* To stop TypeScript complaining about indexing the object with a non-existent key
|
||||||
* https://dev.to/mapleleaf/indexing-objects-in-typescript-1cgi
|
* 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 obj Object with keys to index
|
||||||
* @param key The index key
|
* @param key The index key
|
||||||
* @returns Whether or not the key exists inside the object
|
* @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
|
return key in obj
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue