diff --git a/components/FolderGridLayout.tsx b/components/FolderGridLayout.tsx
new file mode 100644
index 0000000..503256d
--- /dev/null
+++ b/components/FolderGridLayout.tsx
@@ -0,0 +1,83 @@
+import type { OdFolderObject } from '../types'
+
+import Link from 'next/link'
+import emojiRegex from 'emoji-regex'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+
+import { getFileIcon } from '../utils/getFileIcon'
+import { formatModifiedDateTime } from '../utils/fileDetails'
+
+type OdFolderChildren = OdFolderObject['value'][number]
+
+const GridItem = ({ c }: { c: OdFolderChildren }) => {
+ const emojiIcon = emojiRegex().exec(c.name)
+ const renderEmoji = emojiIcon && !emojiIcon.index
+
+ const ChildIcon = () =>
+ renderEmoji ? (
+
{emojiIcon ? emojiIcon[0] : '📁'}
+ ) : (
+
+ )
+
+ // We use the generated medium thumbnail for rendering preview images
+ const thumbnail = c.thumbnails && c.thumbnails.length > 0 ? c.thumbnails[0].medium : null
+
+ return (
+
+
+ {thumbnail ? (
+ // eslint-disable-next-line @next/next/no-img-element
+

+ ) : (
+
+
+
+ {c.folder?.childCount}
+
+
+ )}
+
+
+
+
+
+
+
+ {renderEmoji ? c.name.replace(emojiIcon ? emojiIcon[0] : '', '').trim() : c.name}
+
+
+
+ {formatModifiedDateTime(c.lastModifiedDateTime)}
+
+
+ )
+}
+
+const FolderGridLayout = ({
+ path,
+ folderChildren,
+ selected,
+ toggleItemSelected,
+ totalSelected,
+ toggleTotalSelected,
+ totalGenerating,
+ handleSelectedDownload,
+ folderGenerating,
+ handleFolderDownload,
+ toast,
+}) => {
+ return (
+
+ {folderChildren.map((c: OdFolderChildren) => (
+
+
+
+
+
+ ))}
+
+ )
+}
+
+export default FolderGridLayout
diff --git a/components/FolderListLayout.tsx b/components/FolderListLayout.tsx
new file mode 100644
index 0000000..ed541ec
--- /dev/null
+++ b/components/FolderListLayout.tsx
@@ -0,0 +1,174 @@
+import type { OdFolderObject } from '../types'
+
+import { FC } from 'react'
+import emojiRegex from 'emoji-regex'
+import { useClipboard } from 'use-clipboard-copy'
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
+
+import Link from 'next/link'
+
+import { getBaseUrl } from '../utils/getBaseUrl'
+import { getFileIcon } from '../utils/getFileIcon'
+import { humanFileSize, formatModifiedDateTime } from '../utils/fileDetails'
+
+import { Downloading, Checkbox } from './FileListing'
+
+type OdFolderChildren = OdFolderObject['value'][number]
+
+const FileListItem: FC<{ fileContent: OdFolderChildren }> = ({ fileContent: c }) => {
+ const emojiIcon = emojiRegex().exec(c.name)
+ const renderEmoji = emojiIcon && !emojiIcon.index
+
+ return (
+
+
+ {/*
{c.file ? c.file.mimeType : 'folder'}
*/}
+
+ {renderEmoji ? (
+ {emojiIcon ? emojiIcon[0] : '📁'}
+ ) : (
+
+ )}
+
+
+ {renderEmoji ? c.name.replace(emojiIcon ? emojiIcon[0] : '', '').trim() : c.name}
+
+
+
+ {formatModifiedDateTime(c.lastModifiedDateTime)}
+
+
+ {humanFileSize(c.size)}
+
+
+ )
+}
+
+const FolderListLayout = ({
+ path,
+ folderChildren,
+ selected,
+ toggleItemSelected,
+ totalSelected,
+ toggleTotalSelected,
+ totalGenerating,
+ handleSelectedDownload,
+ folderGenerating,
+ handleFolderDownload,
+ toast,
+}) => {
+ const clipboard = useClipboard()
+
+ return (
+
+
+
+ Name
+
+
+ Last Modified
+
+
+ Size
+
+
+ Actions
+
+
+
+
+ {totalGenerating ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ {folderChildren.map((c: OdFolderChildren) => (
+
+
+
+
+
+
+
+ {c.folder ? (
+
+ {
+ clipboard.copy(`${getBaseUrl()}${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`)
+ toast('Copied folder permalink.', { icon: '👌' })
+ }}
+ >
+
+
+ {folderGenerating[c.id] ? (
+
+ ) : (
+ {
+ const p = `${path === '/' ? '' : path}/${encodeURIComponent(c.name)}`
+ handleFolderDownload(p, c.id, c.name)()
+ }}
+ >
+
+
+ )}
+
+ ) : (
+
+
{
+ clipboard.copy(
+ `${getBaseUrl()}/api?path=${path === '/' ? '' : path}/${encodeURIComponent(c.name)}&raw=true`
+ )
+ toast.success('Copied raw file permalink.')
+ }}
+ >
+
+
+
+
+
+
+ )}
+
+ {!c.folder && !(c.name === '.password') && (
+ toggleItemSelected(c.id)}
+ title="Select file"
+ />
+ )}
+
+
+ ))}
+
+ )
+}
+
+export default FolderListLayout
diff --git a/components/SwitchLayout.tsx b/components/SwitchLayout.tsx
index fbe70ac..fbdbe5c 100644
--- a/components/SwitchLayout.tsx
+++ b/components/SwitchLayout.tsx
@@ -5,9 +5,9 @@ import { Listbox, Transition } from '@headlessui/react'
import useLocalStorage from '../utils/useLocalStorage'
-const layouts: Array<{ id: number; name: 'Grid' | 'List'; icon: IconProp }> = [
- { id: 1, name: 'Grid', icon: 'th' },
- { id: 2, name: 'List', icon: 'th-list' },
+export const layouts: Array<{ id: number; name: 'Grid' | 'List'; icon: IconProp }> = [
+ { id: 1, name: 'List', icon: 'th-list' },
+ { id: 2, name: 'Grid', icon: 'th' },
]
export const SwitchLayout = () => {
diff --git a/pages/_app.tsx b/pages/_app.tsx
index c5ef125..9e4f4eb 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -47,6 +47,7 @@ import {
faExclamationCircle,
faExclamationTriangle,
faTh,
+ faThLarge,
faThList,
faHome,
} from '@fortawesome/free-solid-svg-icons'
@@ -103,6 +104,7 @@ library.add(
faSearch,
faChevronDown,
faTh,
+ faThLarge,
faThList,
...iconList
)
diff --git a/pages/api/index.ts b/pages/api/index.ts
index 5addae6..e4fb79b 100644
--- a/pages/api/index.ts
+++ b/pages/api/index.ts
@@ -220,11 +220,13 @@ export default async function handler(req: NextApiRequest, res: NextApiResponse)
params: next
? {
select: '@microsoft.graph.downloadUrl,name,size,id,lastModifiedDateTime,folder,file,video,image',
+ $expand: 'thumbnails',
top: siteConfig.maxItems,
$skipToken: next,
}
: {
select: '@microsoft.graph.downloadUrl,name,size,id,lastModifiedDateTime,folder,file,video,image',
+ $expand: 'thumbnails',
top: siteConfig.maxItems,
},
})
diff --git a/types/index.d.ts b/types/index.d.ts
index 1872f2f..f3dae85 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -17,6 +17,8 @@ export type OdFolderObject = {
folder?: { childCount: number; view: { sortBy: string; sortOrder: 'ascending'; viewType: 'thumbnails' } }
image?: OdImageFile
video?: OdVideoFile
+ 'thumbnails@odata.context'?: string
+ thumbnails?: Array
}>
}
// A file object returned from the OneDrive API. This object may contain 'video' if the file is a video.