Skip to content

Commit

Permalink
feat: preview a pdf file in task's carousel (#145)
Browse files Browse the repository at this point in the history
  • Loading branch information
hudy9x authored Mar 19, 2024
1 parent 78967de commit 5ed05b1
Show file tree
Hide file tree
Showing 10 changed files with 313 additions and 44 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@
"react-dom": "18.2.0",
"react-hook-form": "^7.44.3",
"react-icons": "^4.9.0",
"react-pdf": "^7.7.1",
"read-excel-file": "^5.6.1",
"resend": "^1.0.0",
"tippy.js": "^6.3.7",
Expand Down
3 changes: 3 additions & 0 deletions packages/ui-app/app/[orgID]/test/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default function Page() {
return <div></div>
}
25 changes: 18 additions & 7 deletions packages/ui-app/app/_components/FileKits/FileCarousel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,25 @@ import {
import { IFileItem, getIconUrl, isImage, useFileKitContext } from './context'
import { HiOutlineDownload } from 'react-icons/hi'
import { useEffect } from 'react'
import PdfViewer from '../PdfViewer'
import './carousel.css'

function FileCarouselDisplay({ file }: { file: IFileItem }) {
if (!file) return null

const isPdf = file.ext.toLowerCase() === 'pdf'
const url = isImage(file.mimeType) ? file.url : getIconUrl(file.ext)

return (
<div className="flex flex-col items-center">
<img src={url} className="max-h-[70vh]" />
<h2 className="text-xl text-gray-200 mt-4 max-w-[450px] text-center">
<div className={`flex flex-col items-center ${isPdf ? 'h-screen' : ''}`}>
{isPdf && file.url ? (
<div className="pt-[50px]">
<PdfViewer src={file.url} />
</div>
) : (
<img src={url} className="max-h-[70vh]" />
)}
<h2 className="text-xl text-gray-200 mt-4 max-w-[450px] text-center pb-[50px]">
{file.name}
</h2>
</div>
Expand Down Expand Up @@ -79,15 +88,17 @@ export default function FileCarousel() {
/>
</div>
</div>
<div className="flex items-center justify-between px-8 h-full">
<div className="flex items-center overflow-y-auto justify-between px-8 h-full">
<HiOutlineChevronLeft
onClick={prevImage}
className="w-14 h-14 p-3 rounded-full bg-white/10 cursor-pointer hover:text-gray-400 text-white"
className="carousel-btn left"
/>
<FileCarouselDisplay file={found} />
<div className="w-full mx-auto">
<FileCarouselDisplay file={found} />
</div>
<HiOutlineChevronRight
onClick={nextImage}
className="w-14 h-14 p-3 rounded-full bg-white/10 cursor-pointer hover:text-gray-400 text-white"
className="carousel-btn right"
/>
</div>
{/* <div onClick={onClose} className="w-full h-full"></div> */}
Expand Down
31 changes: 8 additions & 23 deletions packages/ui-app/app/_components/FileKits/FileItem.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,12 @@
import { Button, Loading, messageSuccess } from '@shared/ui'
import FileThumb from './FileThumb'
import { IFileItem } from './context'
import { IFileItem, isImage } from './context'
import FileDelete from './FileDelete'
import { format, formatDistanceToNow } from 'date-fns'
import { useParams, useSearchParams } from 'next/navigation'
import { taskMakeCover } from '@/services/task'
import { useTaskStore } from '@/store/task'

const generateSizeStr = (size: number) => {
const n = size / 1024
if (n < 1000) {
return `${n.toFixed(2)} Kb`
}

const m = n / 1024

if (m < 1000) {
return `${m.toFixed(2)} Mb`
}

const l = m / 1024

return `${l.toFixed(2)} Gb`
}

export default function FileItem({ data }: { data: IFileItem }) {
const { name, url, ext, mimeType, uploading, id, createdAt } = data
const sp = useSearchParams()
Expand Down Expand Up @@ -81,11 +64,13 @@ export default function FileItem({ data }: { data: IFileItem }) {
<a href={url} target="_blank" className="btn sm">
Download
</a>
<Button
title="Turn this into cover"
size="sm"
onClick={makeThisCover}
/>
{isImage(mimeType) ? (
<Button
title="Turn this into cover"
size="sm"
onClick={makeThisCover}
/>
) : null}
</div>
</div>
</div>
Expand Down
7 changes: 4 additions & 3 deletions packages/ui-app/app/_components/FileKits/FileThumb.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { HiOutlineCamera } from 'react-icons/hi2'
import { HiOutlineCamera, HiOutlineEye } from 'react-icons/hi2'
import { useFileKitContext, isImage, getIconUrl } from './context'

export default function FileThumb({
Expand Down Expand Up @@ -39,13 +39,14 @@ export default function FileThumb({
return (
<div
onClick={onView}
className="bg-gray-100 dark:bg-gray-800 cursor-pointer border-r dark:border-gray-700 rounded-l-md max-h-[150px] w-[120px] shrink-0 flex items-center justify-center">
<div className="relative">
className="relative group bg-gray-100 dark:bg-gray-800 cursor-pointer border-r dark:border-gray-700 rounded-l-md max-h-[150px] w-[120px] shrink-0 flex items-center justify-center">
<div className="">
<img
src={getIconUrl(ext)}
className="w-[50px] px-1 py-1.5 bg-white dark:bg-gray-900 dark:border-gray-700 border rounded-md"
/>
</div>
<HiOutlineEye className="absolute left-2 bottom-2 text-gray-200 group-hover:opacity-100 opacity-0 w-7 h-7 p-1.5 rounded-md bg-black/50" />
</div>
)
}
12 changes: 12 additions & 0 deletions packages/ui-app/app/_components/FileKits/carousel.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
.carousel-btn {
@apply w-14 h-14 p-3 rounded-full bg-white/10 cursor-pointer hover:text-gray-400 text-white;
@apply absolute top-1/2;

&.left {
@apply left-[30px];
}

&.right {
@apply right-[30px];
}
}
30 changes: 30 additions & 0 deletions packages/ui-app/app/_components/PdfViewer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use client'

import { Loading } from '@shared/ui'
import { useState } from 'react'
import { Document, Page } from 'react-pdf'
import 'react-pdf/dist/Page/AnnotationLayer.css'
import 'react-pdf/dist/Page/TextLayer.css'

export default function PdfViewer({ src }: { src: string }) {
const [loading, setLoading] = useState(true)
const [numPages, setNumPages] = useState<number>()
const [pageNumber, setPageNumber] = useState<number>(1)

function onDocumentLoadSuccess({ numPages }: { numPages: number }): void {
setNumPages(numPages)
setLoading(false)
}

return (
<div>
<Loading enabled={loading} title="Parsing..." />
<Document file={src} onLoadSuccess={onDocumentLoadSuccess}>
<Page width={800} pageNumber={pageNumber} />
</Document>
<p>
Page {pageNumber} of {numPages}
</p>
</div>
)
}
6 changes: 6 additions & 0 deletions packages/ui-app/layouts/RootLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
'use client'

import { ThemeProvider } from 'next-themes'
import { pdfjs } from 'react-pdf'

pdfjs.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.js',
import.meta.url
).toString()

export default function RootLayoutComp({
children
Expand Down
16 changes: 10 additions & 6 deletions packages/ui-app/next.config.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//@ts-check

// eslint-disable-next-line @typescript-eslint/no-var-requires
const { composePlugins, withNx } = require('@nx/next');
const { composePlugins, withNx } = require('@nx/next')

/**
* @type {import('@nx/next/plugins/with-nx').WithNxOptions}
Expand All @@ -10,13 +10,17 @@ const nextConfig = {
nx: {
// Set this to true if you would like to use SVGR
// See: https://github.com/gregberge/svgr
svgr: false,
svgr: false
},
};
webpack: config => {
config.resolve.alias.canvas = false
return config
}
}

const plugins = [
// Add more Next.js plugins to this list if needed.
withNx,
];
withNx
]

module.exports = composePlugins(...plugins)(nextConfig);
module.exports = composePlugins(...plugins)(nextConfig)
Loading

0 comments on commit 5ed05b1

Please sign in to comment.