Responsiveness and tabs #179

Merged
enes merged 23 commits from 177-sticky-side-columns into staging 2024-09-05 07:30:55 +00:00
5 changed files with 140 additions and 117 deletions
Showing only changes of commit f8533b0ffd - Show all commits

View File

@ -1,7 +1,5 @@
import { Close } from '@mui/icons-material' import { Close } from '@mui/icons-material'
import { import {
Box,
CircularProgress,
FormControl, FormControl,
InputLabel, InputLabel,
ListItemIcon, ListItemIcon,
@ -22,6 +20,7 @@ import { ExtensionFileBox } from '../ExtensionFileBox'
import { inPx } from '../../utils/pdf' import { inPx } from '../../utils/pdf'
import { useScale } from '../../hooks/useScale' import { useScale } from '../../hooks/useScale'
import { AvatarIconButton } from '../UserAvatarIconButton' import { AvatarIconButton } from '../UserAvatarIconButton'
import { LoadingSpinner } from '../LoadingSpinner'
PDFJS.GlobalWorkerOptions.workerSrc = new URL( PDFJS.GlobalWorkerOptions.workerSrc = new URL(
'pdfjs-dist/build/pdf.worker.min.mjs', 'pdfjs-dist/build/pdf.worker.min.mjs',
@ -530,11 +529,7 @@ export const DrawPDFFields = (props: Props) => {
} }
if (parsingPdf) { if (parsingPdf) {
return ( return <LoadingSpinner variant="small" />
<Box sx={{ width: '100%', textAlign: 'center' }}>
<CircularProgress />
</Box>
)
} }
if (!sigitFiles.length) { if (!sigitFiles.length) {

View File

@ -1,18 +1,31 @@
import styles from './style.module.scss' import styles from './style.module.scss'
interface Props { interface Props {
desc: string desc?: string
variant?: 'small' | 'default'
} }
export const LoadingSpinner = (props: Props) => { export const LoadingSpinner = (props: Props) => {
const { desc } = props const { desc, variant = 'default' } = props
return ( switch (variant) {
<div className={styles.loadingSpinnerOverlay}> case 'small':
<div className={styles.loadingSpinnerContainer}> return (
<div className={styles.loadingSpinner}></div> <div
{desc && <span className={styles.loadingSpinnerDesc}>{desc}</span>} className={`${styles.loadingSpinnerContainer} ${styles.withHeight}`}
</div> >
</div> <div className={styles.loadingSpinner}></div>
) </div>
)
default:
return (
<div className={styles.loadingSpinnerOverlay}>
<div className={styles.loadingSpinnerContainer}>
<div className={styles.loadingSpinner}></div>
{desc && <span className={styles.loadingSpinnerDesc}>{desc}</span>}
</div>
</div>
)
}
} }

View File

@ -11,22 +11,26 @@
justify-content: center; justify-content: center;
background-color: rgba(0, 0, 0, 0.5); background-color: rgba(0, 0, 0, 0.5);
z-index: 9999; z-index: 9999;
}
.loadingSpinnerContainer { .loadingSpinnerContainer {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
}
.loadingSpinner { &.withHeight {
background: url('/favicon.png') no-repeat center / cover; min-height: 250px;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
} }
} }
.loadingSpinner {
background: url('/favicon.png') no-repeat center / cover;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
}
.loadingSpinnerDesc { .loadingSpinnerDesc {
color: white; color: white;
margin-top: 13px; margin-top: 13px;

View File

@ -4,6 +4,7 @@ import { CurrentUserFile } from '../../types/file.ts'
import { useEffect, useRef } from 'react' import { useEffect, useRef } from 'react'
import { FileDivider } from '../FileDivider.tsx' import { FileDivider } from '../FileDivider.tsx'
import React from 'react' import React from 'react'
import { LoadingSpinner } from '../LoadingSpinner/index.tsx'
interface PdfViewProps { interface PdfViewProps {
currentFile: CurrentUserFile | null currentFile: CurrentUserFile | null
@ -48,30 +49,34 @@ const PdfView = ({
index !== files.length - 1 index !== files.length - 1
return ( return (
<div className="files-wrapper"> <div className="files-wrapper">
{files.map((currentUserFile, index, arr) => { {files.length > 0 ? (
const { hash, file, id } = currentUserFile files.map((currentUserFile, index, arr) => {
const { hash, file, id } = currentUserFile
if (!hash) return if (!hash) return
return ( return (
<React.Fragment key={index}> <React.Fragment key={index}>
<div <div
id={file.name} id={file.name}
className="file-wrapper" className="file-wrapper"
ref={(el) => (pdfRefs.current[id] = el)} ref={(el) => (pdfRefs.current[id] = el)}
> >
<PdfItem <PdfItem
file={file} file={file}
currentUserMarks={filterByFile(currentUserMarks, hash)} currentUserMarks={filterByFile(currentUserMarks, hash)}
selectedMark={selectedMark} selectedMark={selectedMark}
handleMarkClick={handleMarkClick} handleMarkClick={handleMarkClick}
selectedMarkValue={selectedMarkValue} selectedMarkValue={selectedMarkValue}
otherUserMarks={filterMarksByFile(otherUserMarks, hash)} otherUserMarks={filterMarksByFile(otherUserMarks, hash)}
/> />
</div> </div>
{isNotLastPdfFile(index, arr) && <FileDivider />} {isNotLastPdfFile(index, arr) && <FileDivider />}
</React.Fragment> </React.Fragment>
) )
})} })
) : (
<LoadingSpinner variant="small" />
)}
</div> </div>
) )
} }

View File

@ -79,74 +79,80 @@ const SlimPdfView = ({
}, [currentFile]) }, [currentFile])
return ( return (
<div className="files-wrapper"> <div className="files-wrapper">
{files.map((currentUserFile, i) => { {files.length > 0 ? (
const { hash, file, id } = currentUserFile files.map((currentUserFile, i) => {
const signatureEvents = Object.keys(parsedSignatureEvents) const { hash, file, id } = currentUserFile
if (!hash) return const signatureEvents = Object.keys(parsedSignatureEvents)
return ( if (!hash) return
<React.Fragment key={file.name}> return (
<div <React.Fragment key={file.name}>
id={file.name} <div
ref={(el) => (pdfRefs.current[id] = el)} id={file.name}
className="file-wrapper" ref={(el) => (pdfRefs.current[id] = el)}
> className="file-wrapper"
{file.isPdf && >
file.pages?.map((page, i) => { {file.isPdf &&
const marks: Mark[] = [] file.pages?.map((page, i) => {
const marks: Mark[] = []
signatureEvents.forEach((e) => { signatureEvents.forEach((e) => {
const m = parsedSignatureEvents[ const m = parsedSignatureEvents[
e as `npub1${string}` e as `npub1${string}`
].parsedContent?.marks.filter( ].parsedContent?.marks.filter(
(m) => m.pdfFileHash == hash && m.location.page == i (m) => m.pdfFileHash == hash && m.location.page == i
)
if (m) {
marks.push(...m)
}
})
return (
<div className="image-wrapper" key={i}>
<img
draggable="false"
src={page.image}
alt={`page ${i} of ${file.name}`}
/>
{marks.map((m) => {
return (
<div
className={`file-mark ${styles.mark}`}
key={m.id}
style={{
left: inPx(from(page.width, m.location.left)),
top: inPx(from(page.width, m.location.top)),
width: inPx(from(page.width, m.location.width)),
height: inPx(
from(page.width, m.location.height)
),
fontFamily: FONT_TYPE,
fontSize: inPx(from(page.width, FONT_SIZE))
}}
>
{m.value}
</div>
)
})}
</div>
) )
if (m) { })}
marks.push(...m) {file.isImage && (
} <img
}) className="file-image"
return ( src={file.objectUrl}
<div className="image-wrapper" key={i}> alt={file.name}
<img />
draggable="false" )}
src={page.image} {!(file.isPdf || file.isImage) && (
alt={`page ${i} of ${file.name}`} <ExtensionFileBox extension={file.extension} />
/> )}
{marks.map((m) => { </div>
return ( {i < files.length - 1 && <FileDivider />}
<div </React.Fragment>
className={`file-mark ${styles.mark}`} )
key={m.id} })
style={{ ) : (
left: inPx(from(page.width, m.location.left)), <LoadingSpinner variant="small" />
top: inPx(from(page.width, m.location.top)), )}
width: inPx(from(page.width, m.location.width)),
height: inPx(from(page.width, m.location.height)),
fontFamily: FONT_TYPE,
fontSize: inPx(from(page.width, FONT_SIZE))
}}
>
{m.value}
</div>
)
})}
</div>
)
})}
{file.isImage && (
<img
className="file-image"
src={file.objectUrl}
alt={file.name}
/>
)}
{!(file.isPdf || file.isImage) && (
<ExtensionFileBox extension={file.extension} />
)}
</div>
{i < files.length - 1 && <FileDivider />}
</React.Fragment>
)
})}
</div> </div>
) )
} }