Add quiz image zoom controls
This commit is contained in:
parent
4f347a18a3
commit
17b0f06037
2 changed files with 64 additions and 7 deletions
|
|
@ -230,20 +230,60 @@ body {
|
|||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: 1000;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 24px;
|
||||
background: rgba(15, 23, 42, 0.82);
|
||||
cursor: zoom-out;
|
||||
}
|
||||
.image-lightbox-viewport {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: auto;
|
||||
cursor: default;
|
||||
}
|
||||
.image-lightbox img {
|
||||
max-width: min(100%, 1100px);
|
||||
max-height: 92vh;
|
||||
display: block;
|
||||
border-radius: 10px;
|
||||
box-shadow: 0 24px 80px rgba(0, 0, 0, 0.35);
|
||||
cursor: default;
|
||||
}
|
||||
.image-lightbox-controls {
|
||||
position: fixed;
|
||||
top: 16px;
|
||||
left: 50%;
|
||||
z-index: 1001;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 7px 9px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.28);
|
||||
border-radius: 999px;
|
||||
background: rgba(15, 23, 42, 0.82);
|
||||
color: white;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
.image-lightbox-controls button {
|
||||
min-width: 34px;
|
||||
height: 30px;
|
||||
padding: 0 10px;
|
||||
border: 1px solid rgba(255, 255, 255, 0.28);
|
||||
border-radius: 999px;
|
||||
background: rgba(255, 255, 255, 0.12);
|
||||
color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
.image-lightbox-controls button:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.45;
|
||||
}
|
||||
.image-lightbox-controls span {
|
||||
min-width: 48px;
|
||||
text-align: center;
|
||||
font-size: 0.86rem;
|
||||
font-weight: 700;
|
||||
}
|
||||
.image-lightbox-close {
|
||||
position: fixed;
|
||||
top: 16px;
|
||||
|
|
|
|||
|
|
@ -398,6 +398,7 @@ export default function QuizPage() {
|
|||
const [toast, setToast] = useState('')
|
||||
const [navOpen, setNavOpen] = useState(false)
|
||||
const [expandedImagePath, setExpandedImagePath] = useState('')
|
||||
const [imageZoom, setImageZoom] = useState(1)
|
||||
const [startedAt, setStartedAt] = useState(null)
|
||||
const [favorites, setFavorites] = useState([])
|
||||
const [activeReadSegment, setActiveReadSegment] = useState(null)
|
||||
|
|
@ -1052,15 +1053,31 @@ const timerStarted = timeLeft !== null
|
|||
{current.question_type === 'mcq' ? 'Multiple Choice' : current.question_type === 'true_false' ? 'True / False' : 'Fill in the Blank'}
|
||||
</span>
|
||||
{current.image_path && (
|
||||
<button className="question-image-preview" onClick={() => setExpandedImagePath(current.image_path)} title="Expand image" type="button">
|
||||
<button className="question-image-preview" onClick={() => { setImageZoom(1); setExpandedImagePath(current.image_path) }} title="Expand image" type="button">
|
||||
<img src={`/uploads/${current.image_path}`} alt="Question illustration"
|
||||
onError={e => e.currentTarget.closest('button').style.display = 'none'} />
|
||||
</button>
|
||||
)}
|
||||
{expandedImagePath && (
|
||||
<div className="image-lightbox" role="dialog" aria-modal="true" aria-label="Expanded question image" onClick={() => setExpandedImagePath('')}>
|
||||
<div className="image-lightbox-controls" onClick={e => e.stopPropagation()}>
|
||||
<button type="button" onClick={() => setImageZoom(z => Math.max(1, z - 0.25))} disabled={imageZoom <= 1}>-</button>
|
||||
<span>{Math.round(imageZoom * 100)}%</span>
|
||||
<button type="button" onClick={() => setImageZoom(z => Math.min(4, z + 0.25))} disabled={imageZoom >= 4}>+</button>
|
||||
<button type="button" onClick={() => setImageZoom(1)} disabled={imageZoom === 1}>Reset</button>
|
||||
</div>
|
||||
<button className="image-lightbox-close" onClick={() => setExpandedImagePath('')} type="button" aria-label="Close expanded image">×</button>
|
||||
<img src={`/uploads/${expandedImagePath}`} alt="Expanded question illustration" onClick={e => e.stopPropagation()} />
|
||||
<div className="image-lightbox-viewport" onClick={e => e.stopPropagation()}>
|
||||
<img
|
||||
src={`/uploads/${expandedImagePath}`}
|
||||
alt="Expanded question illustration"
|
||||
style={{
|
||||
maxWidth: imageZoom === 1 ? 'min(100%, 1100px)' : 'none',
|
||||
maxHeight: imageZoom === 1 ? '92vh' : 'none',
|
||||
width: imageZoom > 1 ? `${imageZoom * 100}%` : undefined,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{(current.question_type === 'mcq' || current.question_type === 'true_false') && current.options ? (
|
||||
|
|
|
|||
Loading…
Reference in a new issue