diff --git a/client/components/anchoredBox.jsx b/client/components/anchoredBox.jsx new file mode 100644 index 000000000..c7d79d2a1 --- /dev/null +++ b/client/components/anchoredBox.jsx @@ -0,0 +1,55 @@ +require('./anchoredBox.less'); +import React, { useState, useRef, useEffect } from 'react'; + +const AnchoredBox = ({ anchorPoint = 'center', className, children, ...props })=>{ + const [visible, setVisible] = useState(false); + const triggerRef = useRef(null); + const boxRef = useRef(null); + + useEffect(()=>{ + const handleClickOutside = (evt)=>{ + if(boxRef.current && + !boxRef.current.contains(evt.target) && + triggerRef.current && + !triggerRef.current.contains(evt.target)){ + setVisible(false); + } + }; + window.addEventListener('click', handleClickOutside); + + const iframe = document.querySelector('iframe'); + if(iframe) { + iframe.addEventListener('load', ()=>{ + const iframeDoc = iframe.contentWindow.document; + if(iframeDoc) { + iframeDoc.addEventListener('click', handleClickOutside); + } + }); + } + + return ()=>{ + window.removeEventListener('click', handleClickOutside); + if(iframe?.contentWindow?.document) { + iframe.contentWindow.document.removeEventListener('click', handleClickOutside); + } + }; + }, []); // Empty dependency array to run effect on mount only + + const handleClick = ()=>{ + setVisible(!visible); + }; + + return ( + <> + +
+

{props.title}

+ {children} +
+ + ); +}; + +export default AnchoredBox; diff --git a/client/components/anchoredBox.less b/client/components/anchoredBox.less new file mode 100644 index 000000000..0f0042ee1 --- /dev/null +++ b/client/components/anchoredBox.less @@ -0,0 +1,57 @@ +.anchored-trigger { + anchor-name: --view-settings; + &.active { + background-color: #444444; + } + +} +.anchored-box { + position-anchor: --view-settings; + position:absolute; + inset-block-start: anchor(bottom); + justify-self: anchor-center; + visibility: hidden; + &.active { + visibility: visible; + } + padding : 15px; + color : white; + background-color : #555555; + border-radius : 5px; + font-size : .8em; + margin-top : 10px; + + h1 { + border-bottom: 1px solid currentColor; + margin-bottom: 0.5em; + padding-bottom: 0.3em; + } + + h2 { + color: lightgray; + border-bottom: 1px solid currentColor; + margin: 1em 0 0.5em 0; + padding-bottom: 0.3em; + } + + label { + display: flex; + align-items: center; + justify-content: space-between; + gap: 6px; + + } + + &:before { + content: ""; + width: 0px; + height: 0px; + position: absolute; + border: 10px solid transparent; + border-bottom: 10px solid #555555; + left: 50%; + transform: translateX(-50%); + top: -20px; + pointer-events: none; + } +} \ No newline at end of file diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 818445714..7b3bb5ad5 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -67,7 +67,8 @@ const BrewRenderer = (props)=>{ height : PAGE_HEIGHT, isMounted : false, visibility : 'hidden', - zoom : 100 + zoom : 100, + pagesStyle : null }); const mainRef = useRef(null); @@ -187,6 +188,13 @@ const BrewRenderer = (props)=>{ })); }; + const handleStyle = (newStyle)=>{ + setState((prevState)=>({ + ...prevState, + pagesStyle : { ...prevState.pagesStyle, ...newStyle }, + })); + }; + return ( <> {/*render dummy page while iFrame is mounting.*/} @@ -204,7 +212,7 @@ const BrewRenderer = (props)=>{ - + {/*render in iFrame so broken code doesn't crash the site.*/} { && <> {renderStyle()} -
+
{renderPages()}
diff --git a/client/homebrew/brewRenderer/toolBar/toolBar.jsx b/client/homebrew/brewRenderer/toolBar/toolBar.jsx index 58071320e..af4d906c0 100644 --- a/client/homebrew/brewRenderer/toolBar/toolBar.jsx +++ b/client/homebrew/brewRenderer/toolBar/toolBar.jsx @@ -3,16 +3,19 @@ const React = require('react'); const { useState, useEffect } = React; const _ = require('lodash'); +import AnchoredBox from '../../../components/anchoredBox.jsx'; +// import * as ZoomIcons from '../../../icons/icon-components/zoomIcons.jsx'; const MAX_ZOOM = 300; const MIN_ZOOM = 10; -const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{ +const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages, onStyleChange })=>{ const [zoomLevel, setZoomLevel] = useState(100); const [pageNum, setPageNum] = useState(currentPage); const [arrangement, setArrangement] = useState('single'); const [startOnRight, setStartOnRight] = useState(true); + const [pagesStyle, setPagesStyle] = useState({}); const [toolsVisible, setToolsVisible] = useState(true); const modes = ['single', 'facing', 'flow']; @@ -25,6 +28,7 @@ const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{ }, [currentPage]);; // update display arrangement when arrangement state is changed. + // todo: do this the 'react' way, without querying the dom. useEffect(()=>{ const iframe = document.getElementById('BrewRenderer'); const pagesContainer = iframe?.contentWindow?.document.querySelector('.pages'); @@ -35,7 +39,6 @@ const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{ ['recto', 'verso'].forEach((leaf)=>pagesContainer.classList.remove(leaf)); pagesContainer.classList.add(startOnRight ? 'recto' : 'verso'); } - }, [arrangement]); }, [arrangement, startOnRight]); @@ -152,6 +155,19 @@ const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{ > {arrangement} + + + + +

Facing

+ +
diff --git a/client/homebrew/brewRenderer/toolBar/toolBar.less b/client/homebrew/brewRenderer/toolBar/toolBar.less index e26197462..782730e54 100644 --- a/client/homebrew/brewRenderer/toolBar/toolBar.less +++ b/client/homebrew/brewRenderer/toolBar/toolBar.less @@ -34,6 +34,13 @@ align-items : center; } + .anchored-box { + color: #CCCCCC; + input[type='number']{ + width: 4ch; + } + } + input { position : relative; height : 1.5em;