0
0
mirror of https://github.com/naturalcrit/homebrewery.git synced 2025-12-30 19:42:43 +00:00
Files
homebrewery/client/homebrew/brewRenderer/toolBar/toolBar.jsx
Gazook89 49a4daa8f6 useEffect hook to update view after mode select
utilize useEffect hook to trigger render when the mode state is changed.

Move modes array to top level array, and change 'book-mode' to 'facing', and add 'flow' mode.

toggle modes as class names in .pages div, which are each styled as required.
2024-08-23 14:29:02 -05:00

213 lines
5.5 KiB
JavaScript

require('./toolBar.less');
const React = require('react');
const { useState, useEffect } = React;
const _ = require('lodash')
import * as ZoomIcons from '../../../icons/icon-components/zoomIcons.jsx';
const MAX_ZOOM = 300;
const MIN_ZOOM = 10;
const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{
const [zoomLevel, setZoomLevel] = useState(100);
const [pageInput, setPageInput] = useState(currentPage);
const [arrangement, setArrangement] = useState('single');
const modes = ['single', 'facing', 'flow'];
useEffect(()=>{
onZoomChange(zoomLevel);
}, [zoomLevel]);
useEffect(()=>{
setPageInput(currentPage);
}, [currentPage]);
// update display arrangement when arrangement state is changed.
useEffect(()=>{
const iframe = document.getElementById('BrewRenderer');
const pagesContainer = iframe?.contentWindow?.document.querySelector('.pages');
if(pagesContainer) {
modes.forEach((mode)=>pagesContainer.classList.remove(mode));
pagesContainer.classList.add(arrangement);
}
}, [arrangement]);
const handleZoomChange = (delta)=>{
const zoomChange = _.clamp(zoomLevel + delta, MIN_ZOOM, MAX_ZOOM);
setZoomLevel(zoomChange);
};
const handlePageChange = (page)=>{
setPageInput(page);
};
const scrollToPage = (pageNumber) => {
pageNumber = _.clamp(pageNumber - 1, 0, totalPages - 1);
const iframe = document.getElementById('BrewRenderer');
if(iframe && iframe.contentWindow) {
const brewRenderer = iframe.contentWindow.document.querySelector('.brewRenderer');
if(brewRenderer) {
const pages = brewRenderer.querySelectorAll('.page');
pages[pageNumber]?.scrollIntoView({ block: 'start' });
}
}
};
const calculateZoom = (mode)=>{
const iframe = document.getElementById('BrewRenderer');
const iframeWidth = iframe.getBoundingClientRect().width;
const iframeHeight = iframe.getBoundingClientRect().height;
const pages = iframe.contentWindow.document.getElementsByClassName('page');
let desiredZoom = 0;
if(mode == 'fill'){
// find widest page, in case pages are different widths, so that the zoom is adapted to not cut the widest page off screen.
let widestPage = 0;
[...pages].forEach((page)=>{
const width = page.offsetWidth;
if(width > widestPage)
widestPage = width;
});
desiredZoom = (iframeWidth / widestPage) * 100;
} else if(mode == 'fit'){
// find the page with the largest single dim (height or width) so that zoom can be adapted to fit it.
let maxDimRatio = 0;
[...pages].forEach((page)=>{
const widthRatio = iframeWidth / page.offsetWidth;
const heightRatio = iframeHeight / page.offsetHeight;
const dimensionRatio = Math.min(widthRatio, heightRatio);
if(dimensionRatio < maxDimRatio || maxDimRatio == 0){
maxDimRatio = dimensionRatio;
}
});
desiredZoom = maxDimRatio * 100;
}
const margin = 5; // extra space so page isn't edge to edge (not truly "to fill")
const deltaZoom = (desiredZoom - zoomLevel) - margin;
return deltaZoom;
};
const setBookMode = ()=>{
const nextMode = modes[(modes.indexOf(arrangement) + 1) % modes.length];
setArrangement(nextMode);
};
return (
<div className='toolBar'>
<div className='group'>
<button
id='zoom-to-fill'
className='tool'
onClick={()=>handleZoomChange(calculateZoom('fill'))}
>
<ZoomIcons.FitWidth title='Fit to Width' style={{ width: '1.5em' }} />
</button>
<button
id='zoom-to-fit'
className='tool'
onClick={()=>handleZoomChange(calculateZoom('fit'))}
>
<ZoomIcons.FitAll title='Zoom to Fit' style={{ width: '1.5em' }} />
</button>
<button
id='zoom-out'
className='tool'
onClick={()=>handleZoomChange(-20)}
disabled={zoomLevel <= MIN_ZOOM}
>
<i className='fas fa-magnifying-glass-minus' />
</button>
<input
id='zoom-slider'
className='range-input tool'
type='range'
name='zoom'
list='zoomLevels'
min={MIN_ZOOM}
max={MAX_ZOOM}
step='1'
value={zoomLevel}
onChange={(e)=>{setZoomLevel(parseInt(e.target.value));}}
/>
<datalist id='zoomLevels'>
<option value='100' />
</datalist>
<button
id='zoom-in'
className='tool'
onClick={()=>handleZoomChange(20)}
disabled={zoomLevel >= MAX_ZOOM}
>
<i className='fas fa-magnifying-glass-plus' />
</button>
</div>
<div className='group'>
<button
id='book-mode'
className='tool'
onClick={()=>setBookMode()}
>
{arrangement}
</button>
</div>
<div className='group'>
<button
id='previous-page'
className='previousPage tool'
onClick={()=>scrollToPage(pageInput - 1)}
disabled={pageInput <= 1}
>
<i className='fas fa-arrow-left'></i>
</button>
<div className='tool'>
<input
id='page-input'
className='text-input'
type='text'
name='page'
inputMode='numeric'
pattern='[0-9]'
value={pageInput}
onChange={(e)=>{
handlePageChange(e.target.value == false ? e.target.value : parseInt(e.target.value));}}
onBlur={()=>scrollToPage(pageInput)}
onKeyDown={(e)=>{e.key == 'Enter' ? scrollToPage(pageInput) : null;}}
/>
<span id='page-count'>/ {totalPages}</span>
</div>
<button
id='next-page'
className='tool'
onClick={()=>scrollToPage(pageInput + 1)}
disabled={pageInput >= totalPages}
>
<i className='fas fa-arrow-right'></i>
</button>
</div>
</div>
);
};
module.exports = ToolBar;