Skip to content

Commit

Permalink
Add PagesCardToolbar component for image navigation and zoom controls
Browse files Browse the repository at this point in the history
  • Loading branch information
IonMich committed Feb 13, 2025
1 parent 746a1f5 commit 59ff9f4
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 60 deletions.
83 changes: 83 additions & 0 deletions frontend/src/components/pages-card-toolbar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import * as React from "react"
import { LuArrowUp, LuArrowDown, LuZoomIn, LuZoomOut } from "react-icons/lu"
import { Separator } from "@/components/ui/separator"

interface PagesCardToolbarProps {
pageValue: number
setPageValue: (value: number) => void
numImages: number
pagesContainerRef: React.RefObject<HTMLDivElement>
zoomImgPercent: number
setZoomImgPercent: (value: number) => void
isScrolling: boolean
}

export function PagesCardToolbar({
pageValue,
setPageValue,
numImages,
pagesContainerRef,
zoomImgPercent,
setZoomImgPercent,
isScrolling,
}: PagesCardToolbarProps) {
const scrollToPage = (newPage: number) => {
if (pagesContainerRef.current) {
const scrollHeight = pagesContainerRef.current.scrollHeight
pagesContainerRef.current.scrollTop = (scrollHeight / numImages) * (newPage - 1)
}
}
return (
<div
// Added frosted glass effect on hover with backdrop-blur and semi-transparent background
className={`absolute top-[5px] left-1/2 transform -translate-x-1/2 rounded-xl py-2 px-8 text-center backdrop-blur-md bg-white/30 transition-all duration-300 flex items-center justify-center
${isScrolling ? "opacity-50" : "opacity-0 hover:opacity-100"}`}
>
<button
onClick={() => {
if (pageValue > 1) {
const newPage = pageValue - 1
setPageValue(newPage)
scrollToPage(newPage)
}
}}
>
<LuArrowUp />
</button>
<span className="mx-2">
Page <span className="w-[2ch] inline-block text-center">{pageValue}</span> of {numImages}
</span>
<button
onClick={() => {
if (pageValue < numImages) {
const newPage = pageValue + 1
setPageValue(newPage)
scrollToPage(newPage)
}
}}
>
<LuArrowDown />
</button>
<Separator orientation="vertical" className="mx-4" />
<button
onClick={() => {
if (zoomImgPercent > 50) setZoomImgPercent(zoomImgPercent - 10)
}}
aria-label="Zoom Out"
disabled={zoomImgPercent <= 50}
>
<LuZoomOut />
</button>
<span className="text-sm mx-2">{zoomImgPercent}%</span>
<button
onClick={() => {
if (zoomImgPercent < 100) setZoomImgPercent(zoomImgPercent + 10)
}}
aria-label="Zoom In"
disabled={zoomImgPercent >= 100}
>
<LuZoomIn />
</button>
</div>
)
}
85 changes: 58 additions & 27 deletions frontend/src/routes/-components/submissionDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
submissionQueryOptions,
submissionsQueryOptions,
} from "@/utils/queryOptions"
import { PagesCardToolbar } from "@/components/pages-card-toolbar"

function findPrevSubmission(submission: Submission, submissions: Submission[]) {
const currentSubmissionIndex = submissions.findIndex(
Expand Down Expand Up @@ -104,6 +105,15 @@ export function SubmissionDetail({
const images = submission?.papersubmission_images ?? []
const numImages = images.length

const [isScrolling, setIsScrolling] = React.useState(false)

React.useEffect(() => {
if (isScrolling) {
const timer = setTimeout(() => setIsScrolling(false), 1000)
return () => clearTimeout(timer)
}
}, [isScrolling])

React.useEffect(() => {
setFullRenderSuccess(false)
}, [submission.id, rendeder])
Expand Down Expand Up @@ -143,8 +153,6 @@ export function SubmissionDetail({
>
<Card className="md:h-[85vh] col-span-2 p-4 hidden lg:flex my-2 flex-col gap-4">
<LeftSidebar
pageValue={pageValue}
setPageValue={setPageValue}
initialQuestionFocus={initialQuestionFocus}
setInitialQuestionFocus={setInitialQuestionFocus}
zoomImgPercent={zoomImgPercent}
Expand All @@ -153,38 +161,61 @@ export function SubmissionDetail({
setAnonymousGrading={setAnonymousGrading}
rendeder={rendeder}
setRenderer={setRenderer}
images={images}
submission={submission}
containerRef={pagesContainerRef}
/>
</Card>
<div className="lg:col-span-5 md:col-span-7 col-span-9 md:py-2 py-0">
<Card
ref={pagesContainerRef}
className={cn(
"h-[70vh] md:h-[85vh] overflow-y-auto",
allImgsLoaded ? "bg-gray-500" : "bg-accent"
)}
>
{rendeder === "images" ? (
// ----Image Rendering----
<PagesScrollArea
images={images}
<div className="relative group">
<Card
ref={pagesContainerRef}
onScroll={(e) => {
setIsScrolling(true)
const scrollTop = e.currentTarget.scrollTop
const scrollHeight = e.currentTarget.scrollHeight
const pageHeight = numImages ? scrollHeight / numImages : 0
const newPage =
numImages && pageHeight
? Math.floor((scrollTop + pageHeight / 3) / pageHeight) + 1
: 1
if (newPage !== pageValue) {
setPageValue(newPage)
}
}}
className={cn(
"h-[70vh] md:h-[85vh] overflow-y-auto",
allImgsLoaded ? "bg-gray-500" : "bg-accent"
)}
>
<PagesCardToolbar
pageValue={pageValue}
setPageValue={setPageValue}
numImages={numImages}
pagesContainerRef={pagesContainerRef}
zoomImgPercent={zoomImgPercent}
allImgsLoaded={allImgsLoaded}
anonymousGrading={anonymousGrading}
setFullRenderSuccess={setFullRenderSuccess}
/>
) : (
// ----PDF Rendering----
<PdfViewer
url={submission.pdf}
zoom_percent={zoomImgPercent}
anonymousGrading={anonymousGrading}
setFullRenderSuccess={setFullRenderSuccess}
setZoomImgPercent={setZoomImgPercent}
isScrolling={isScrolling}
/>
)}
</Card>
{rendeder === "images" ? (
// ----Image Rendering----
<PagesScrollArea
images={images}
zoomImgPercent={zoomImgPercent}
allImgsLoaded={allImgsLoaded}
anonymousGrading={anonymousGrading}
setFullRenderSuccess={setFullRenderSuccess}
/>
) : (
// ----PDF Rendering----
<PdfViewer
url={submission.pdf}
zoom_percent={zoomImgPercent}
anonymousGrading={anonymousGrading}
setFullRenderSuccess={setFullRenderSuccess}
/>
)}
</Card>
</div>
</div>
{/* Right sidebar */}
<RightSidebar
Expand Down
33 changes: 0 additions & 33 deletions frontend/src/routes/-components/submissionLeftSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,8 +123,6 @@ export function InfoExtractedSidebar({
}

export function SubmissionSettingsSidebar({
pageValue,
setPageValue,
initialQuestionFocus,
setInitialQuestionFocus,
zoomImgPercent,
Expand All @@ -133,11 +131,7 @@ export function SubmissionSettingsSidebar({
setAnonymousGrading,
rendeder,
setRenderer,
images,
containerRef,
}: {
pageValue: number
setPageValue: (value: number) => void
initialQuestionFocus: number | null
setInitialQuestionFocus: (value: number | null) => void
zoomImgPercent: number
Expand All @@ -146,26 +140,9 @@ export function SubmissionSettingsSidebar({
setAnonymousGrading: (value: boolean) => void
rendeder: "pdf" | "images"
setRenderer: (value: "pdf" | "images") => void
images: PaperSubmissionImage[]
containerRef: React.RefObject<HTMLDivElement>
}) {
return (
<>
<Button
variant="outline"
size="sm"
onClick={() => {
const newPageValue = (pageValue % images.length) + 1
setPageValue(newPageValue)
if (containerRef.current) {
const cardDiv = containerRef.current
cardDiv.scrollTop =
(cardDiv.scrollHeight / images.length) * (newPageValue - 1)
}
}}
>
Page {pageValue} of {images.length}
</Button>
<Button
variant="outline"
size="sm"
Expand Down Expand Up @@ -210,8 +187,6 @@ export function SubmissionSettingsSidebar({
}

export function LeftSidebar({
pageValue,
setPageValue,
initialQuestionFocus,
setInitialQuestionFocus,
zoomImgPercent,
Expand All @@ -220,12 +195,9 @@ export function LeftSidebar({
setAnonymousGrading,
rendeder,
setRenderer,
images,
submission,
containerRef,
}: {
pageValue: number
setPageValue: (value: number) => void
initialQuestionFocus: number | null
setInitialQuestionFocus: (value: number | null) => void
zoomImgPercent: number
Expand All @@ -234,7 +206,6 @@ export function LeftSidebar({
setAnonymousGrading: (value: boolean) => void
rendeder: "pdf" | "images"
setRenderer: (value: "pdf" | "images") => void
images: PaperSubmissionImage[]
submission: Submission
containerRef: React.RefObject<HTMLDivElement>
}) {
Expand All @@ -255,8 +226,6 @@ export function LeftSidebar({
</TabsList>
<TabsContent value="controls" className="flex flex-col gap-4">
<SubmissionSettingsSidebar
pageValue={pageValue}
setPageValue={setPageValue}
initialQuestionFocus={initialQuestionFocus}
setInitialQuestionFocus={setInitialQuestionFocus}
zoomImgPercent={zoomImgPercent}
Expand All @@ -265,8 +234,6 @@ export function LeftSidebar({
setAnonymousGrading={setAnonymousGrading}
rendeder={rendeder}
setRenderer={setRenderer}
images={images}
containerRef={containerRef}
/>
</TabsContent>
<TabsContent value="info">
Expand Down

0 comments on commit 59ff9f4

Please sign in to comment.