diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx index 4b82c6bc0..f3b284a93 100644 --- a/client/homebrew/brewRenderer/brewRenderer.jsx +++ b/client/homebrew/brewRenderer/brewRenderer.jsx @@ -7,6 +7,7 @@ const _ = require('lodash'); const MarkdownLegacy = require('naturalcrit/markdownLegacy.js'); const Markdown = require('naturalcrit/markdown.js'); const ErrorBar = require('./errorBar/errorBar.jsx'); +const ToolBar = require('./toolBar/toolBar.jsx'); //TODO: move to the brew renderer const RenderWarnings = require('homebrewery/renderWarnings/renderWarnings.jsx'); @@ -60,10 +61,11 @@ const BrewRenderer = (props)=>{ }; const [state, setState] = useState({ - viewablePageNumber : 0, - height : PAGE_HEIGHT, - isMounted : false, - visibility : 'hidden', + height : PAGE_HEIGHT, + isMounted : false, + visibility : 'hidden', + zoom : 100, + currentPageNumber : 1, }); const mainRef = useRef(null); @@ -85,11 +87,14 @@ const BrewRenderer = (props)=>{ })); }; - const handleScroll = (e)=>{ - const target = e.target; + const getCurrentPage = (e)=>{ + const { scrollTop, clientHeight, scrollHeight } = e.target; + const totalScrollableHeight = scrollHeight - clientHeight; + const currentPageNumber = Math.ceil((scrollTop / totalScrollableHeight) * rawPages.length); + setState((prevState)=>({ ...prevState, - viewablePageNumber : Math.floor(target.scrollTop / target.scrollHeight * rawPages.length) + currentPageNumber : currentPageNumber || 1 })); }; @@ -100,23 +105,12 @@ const BrewRenderer = (props)=>{ if(index == props.currentEditorPage) //Already rendered before this step return false; - if(Math.abs(index - state.viewablePageNumber) <= 3) + if(Math.abs(index - state.currentPageNumber) <= 3) return true; return false; }; - const renderPageInfo = ()=>{ - return
-
- {props.renderer} -
-
- {state.viewablePageNumber + 1} / {rawPages.length} -
-
; - }; - const renderDummyPage = (index)=>{ return
@@ -186,11 +180,19 @@ const BrewRenderer = (props)=>{ document.dispatchEvent(new MouseEvent('click')); }; + //Toolbar settings: + const handleZoom = (newZoom)=>{ + setState((prevState)=>({ + ...prevState, + zoom : newZoom + })); + }; + return ( <> {/*render dummy page while iFrame is mounting.*/} {!state.isMounted - ?
+ ?
{renderDummyPage(1)}
@@ -198,11 +200,13 @@ const BrewRenderer = (props)=>{ : null} -
+
+ + {/*render in iFrame so broken code doesn't crash the site.*/} { onClick={()=>{emitClick();}} >
+ {/* Apply CSS from Style tab and render pages from Markdown tab */} {state.isMounted && <> {renderStyle()} -
+
{renderPages()}
}
- {renderPageInfo()} ); }; diff --git a/client/homebrew/brewRenderer/brewRenderer.less b/client/homebrew/brewRenderer/brewRenderer.less index 28ea8005e..234624aa2 100644 --- a/client/homebrew/brewRenderer/brewRenderer.less +++ b/client/homebrew/brewRenderer/brewRenderer.less @@ -1,8 +1,9 @@ @import (multiple, less) 'shared/naturalcrit/styles/reset.less'; .brewRenderer { - will-change : transform; - overflow-y : scroll; + padding-top : 30px; + overflow-y : scroll; + will-change : transform; :where(.pages) { margin : 30px 0px; & > :where(.page) { @@ -14,66 +15,31 @@ box-shadow : 1px 4px 14px #000000; } } - &::-webkit-scrollbar { - width: 20px; - &:horizontal{ - height: 20px; - width:auto; + width : 20px; + &:horizontal { + width : auto; + height : 20px; } &-thumb { - background: linear-gradient(90deg, #d3c1af 15px, #00000000 15px); - &:horizontal{ - background: linear-gradient(0deg, #d3c1af 15px, #00000000 15px); - } - } - &-corner { - visibility: hidden; + background : linear-gradient(90deg, #D3C1AF 15px, #00000000 15px); + &:horizontal { background : linear-gradient(0deg, #D3C1AF 15px, #00000000 15px); } } + &-corner { visibility : hidden; } } - - - - - } + .pane { position : relative; } -.pageInfo { - position : absolute; - right : 17px; - bottom : 0; - z-index : 1000; - font-size : 10px; - font-weight : 800; - color : white; - background-color : #333333; - div { - display : inline-block; - padding : 8px 10px; - &:not(:last-child) { border-right : 1px solid #666666; } - } -} -.ppr_msg { - position : absolute; - bottom : 0; - left : 0px; - z-index : 1000; - padding : 8px 10px; - font-size : 10px; - font-weight : 800; - color : white; - background-color : #333333; -} @media print { + .toolBar { display : none; } .brewRenderer { - height: 100%; - overflow-y: unset; + height : 100%; + padding-top : unset; + overflow-y : unset; .pages { - margin: 0px; - &>.page { - box-shadow: unset; - } + margin : 0px; + & > .page { box-shadow : unset; } } } } \ No newline at end of file diff --git a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less index 26d764aff..2982055c8 100644 --- a/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less +++ b/client/homebrew/brewRenderer/notificationPopup/notificationPopup.less @@ -1,9 +1,10 @@ .popups { position : fixed; - top : @navbarHeight; + top : calc(@navbarHeight + @viewerToolsHeight); right : 24px; z-index : 10001; width : 450px; + margin-top : 5px; } .notificationPopup { diff --git a/client/homebrew/brewRenderer/toolBar/toolBar.jsx b/client/homebrew/brewRenderer/toolBar/toolBar.jsx new file mode 100644 index 000000000..8ad14ae9b --- /dev/null +++ b/client/homebrew/brewRenderer/toolBar/toolBar.jsx @@ -0,0 +1,119 @@ +require('./toolBar.less'); +const React = require('react'); +const { useState, useEffect } = React; +const _ = require('lodash'); + +const MAX_ZOOM = 300; +const MIN_ZOOM = 10; + +const ToolBar = ({ onZoomChange, currentPage, onPageChange, totalPages })=>{ + + const [zoomLevel, setZoomLevel] = useState(100); + const [pageNum, setPageNum] = useState(currentPage); + + useEffect(()=>{ + onZoomChange(zoomLevel); + }, [zoomLevel]); + + useEffect(()=>{ + setPageNum(currentPage); + }, [currentPage]); + + const handleZoomButton = (delta)=>{ + setZoomLevel(_.clamp(zoomLevel + delta, MIN_ZOOM, MAX_ZOOM)); + }; + + const handlePageInput = (pageInput)=>{ + if(/[0-9]/.test(pageInput)) + setPageNum(parseInt(pageInput)); // input type is 'text', so `page` comes in as a string, not number. + }; + + const scrollToPage = (pageNumber)=>{ + pageNumber = _.clamp(pageNumber, 1, totalPages); + const iframe = document.getElementById('BrewRenderer'); + const brewRenderer = iframe?.contentWindow?.document.querySelector('.brewRenderer'); + const page = brewRenderer?.querySelector(`#p${pageNumber}`); + page?.scrollIntoView({ block: 'start' }); + setPageNum(pageNumber); + }; + + return ( +
+ {/*v=====----------------------< Zoom Controls >---------------------=====v*/} +
+ + setZoomLevel(parseInt(e.target.value))} + /> + + + + +
+ + {/*v=====----------------------< Page Controls >---------------------=====v*/} +
+ + +
+ e.target.select()} + onChange={(e)=>handlePageInput(e.target.value)} + onBlur={()=>scrollToPage(pageNum)} + onKeyDown={(e)=>e.key == 'Enter' && scrollToPage(pageNum)} + /> + / {totalPages} +
+ + +
+
+ ); +}; + +module.exports = ToolBar; diff --git a/client/homebrew/brewRenderer/toolBar/toolBar.less b/client/homebrew/brewRenderer/toolBar/toolBar.less new file mode 100644 index 000000000..33a6836ef --- /dev/null +++ b/client/homebrew/brewRenderer/toolBar/toolBar.less @@ -0,0 +1,98 @@ +.toolBar { + position : absolute; + z-index : 1; + box-sizing : border-box; + display : flex; + flex-wrap : wrap; + gap : 8px 30px; + align-items : center; + justify-content : center; + width : 100%; + height : auto; + padding : 2px 0; + font-family : 'Open Sans', sans-serif; + color : #CCCCCC; + background-color : #555555; + + .group { + box-sizing : border-box; + display : flex; + gap : 0 3px; + align-items : center; + justify-content : center; + height : 28px; + } + + .tool { + display : flex; + align-items : center; + } + + input { + position : relative; + height : 1.5em; + padding : 2px 5px; + font-family : 'Open Sans', sans-serif; + color : #000000; + background : #EEEEEE; + border : 1px solid gray; + &:focus { outline : 1px solid #D3D3D3; } + + // `.range-input` if generic to all range inputs, or `#zoom-slider` if only for zoom slider + &.range-input { + padding : 2px 0; + color : #D3D3D3; + accent-color : #D3D3D3; + + &::-webkit-slider-thumb, &::-moz-slider-thumb { + width : 5px; + height : 5px; + cursor : pointer; + outline : none; + } + + &:hover::after { + position : absolute; + bottom : -30px; + left : 50%; + z-index : 1; + display : grid; + place-items : center; + width : 4ch; + height : 1.2lh; + pointer-events : none; + content : attr(value); + background-color : #555555; + border : 1px solid #A1A1A1; + transform : translate(-50%, 50%); + } + } + + // `.text-input` if generic to all range inputs, or `#page-input` if only for current page input + &#page-input { + width : 4ch; + margin-right : 1ch; + text-align : center; + } + } + + button { + box-sizing : content-box; + display : flex; + align-items : center; + justify-content : center; + width : auto; + min-width : 46px; + height : 100%; + padding : 0 0px; + font-weight : unset; + color : inherit; + background-color : unset; + &:hover { background-color : #444444; } + &:focus { outline : 1px solid #D3D3D3; } + &:disabled { + color : #777777; + background-color : unset !important; + } + } +} \ No newline at end of file diff --git a/client/homebrew/editor/editor.jsx b/client/homebrew/editor/editor.jsx index 41d3f91e4..3757b2c9e 100644 --- a/client/homebrew/editor/editor.jsx +++ b/client/homebrew/editor/editor.jsx @@ -86,7 +86,6 @@ const Editor = createClass({ handleControlKeys : function(e){ if(!(e.ctrlKey || e.metaKey)) return; - console.log(e); const LEFTARROW_KEY = 37; const RIGHTARROW_KEY = 39; if (e.shiftKey && (e.keyCode == RIGHTARROW_KEY)) this.brewJump(); diff --git a/client/homebrew/navbar/navbar.less b/client/homebrew/navbar/navbar.less index d0f2f77e8..4525a193e 100644 --- a/client/homebrew/navbar/navbar.less +++ b/client/homebrew/navbar/navbar.less @@ -1,6 +1,7 @@ @import 'naturalcrit/styles/colors.less'; @navbarHeight : 28px; +@viewerToolsHeight : 32px; @keyframes pinkColoring { 0% { color : pink; }