From fe277a7bf4220b2de79a1516feb688817900b48c Mon Sep 17 00:00:00 2001 From: Tom Najdek Date: Thu, 31 Aug 2023 19:27:46 +0200 Subject: [PATCH] Add thumbnails header with extra UI for web target --- res/icons/more-horizontal.png | Bin 0 -> 1161 bytes res/icons/more-horizontal@2x.png | Bin 0 -> 1202 bytes .../components/sidebar/thumbnails-view.js | 87 ++++++++++++------ .../components/_thumbnails-view.scss | 55 +++++++++-- .../stylesheets/themes/_light-darwin.scss | 1 + src/en-us.strings.js | 4 +- 6 files changed, 110 insertions(+), 37 deletions(-) create mode 100644 res/icons/more-horizontal.png create mode 100644 res/icons/more-horizontal@2x.png diff --git a/res/icons/more-horizontal.png b/res/icons/more-horizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..c8839ecbbc18fe5f9648898c13d62744a095b736 GIT binary patch literal 1161 zcmZ`&zi-n(6h1dlN@y04P*oU=St?L`wxbs1{Zb0nFW+>Cd>W7_$Nx8NrHf z!W_J@(4`pv3M3m9nBXar4J$B*wn1HwZ+I?W5DTJQKxk#UGUKgJGjp9e_+F~*gSa}X zbbN%a-C&bLryn*D%Gg$`P22Sv>AALO^xdv02KI=tkQxwBZIc>&U=JOi1SKIv5YX8+ z7WfcCUzCJ)y}|Fgp2_csk|+sUmgjlZ>kmj%e;m`{uOvLDbVM+oOeW%_AiCZ$mW#zA zmK3Zgc|hd-mku?8yyM@EoSga5O~2<^BWk%0&-@x)cT7uyzyi%il&2Y3^GJ>#mjwl4 zX2G&3;YBnkc9!2cR$z>llBhLU5{p?PT6h>yjw;K5gqPUSE!%W_s7I3(HB9Y-VP0H< z*j`3V7!pJ%i|l$PYnhho4z-0Hq~bIz<)IGu-8ZPA8`RVkNh#!|VqTJ4@-|V5WLv&3 zDMXSYH|MYkKkP(EyJ`CFaLn#ed!R@#u*_B!UofYsbLN3#Q4J0)q@=dftj^rNC}7f@ zrtW)|3EddxD#y{1dof|;+}e8AJKFd( oolbw9l*`{vy8mjK-(T-sL25Pk^Z3V?9rg^XkM{J>5075|2N)GO`v3p{ literal 0 HcmV?d00001 diff --git a/res/icons/more-horizontal@2x.png b/res/icons/more-horizontal@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..5f8b65dd62c3244df9d4f18ea79e5e04b81cc3f3 GIT binary patch literal 1202 zcmZ`&-D}fO6u<30tkpf}s+7%#7(W=3<|b(;G^AnLs4c9slsZ};WLcNGV4IZWj%K1h z>_z4Wh={NWGMLZ9C&4%W2=Unm{{Zo6kDi-kZPu+f+LQ9e9p8hB@6JVl% z5fH5CBFyGX1C0jwXCUc#2NOK`vTV3|tE~~sX3Dn3q`5RFq!EhlMti*E?nqy!4nDFg zA3&V$6zUFyxkhKCSh@Nap%Kfd)<~_iAT_Kur>$BmI_I`Kl!ath0=2CZjd9y8(~;a9 z>mel2={9B=4?>>g*jlN~aNj` zWI91vP#~rjEO0zNi3Y{?@;kzEwa!oyF`7eSQHxLW4#Uq;rWr`yCDv7=t(y+iqlg*V zOYNAUUtEY-8%7KnLPRJ_%G)|^nW|;AloLBh#)Gf{4<)$oRgGw>Ms!8w#dM0#rg)($ z%t>ip%FNy1MTzHqH%G7`KlDVTT19uP);hgMMaX1$7+9dIjE~s|xqa#b(;$i%PzJUK zS@pjC#E4=0Aosp)=+KXTwn4b?UVxV|ZOKrJ`u*?i!UIs^a4?6DNr_K?e!UIvD_>M^ zRSR2<<>c7ja^mdsAF)Ovk)S8?GynbV7~}IKigktzRb>l+dX&c g)5Cv2c(Zx=4Ei;CA-1tse?i}C@y?>Ue|vfJKTZrr)&Kwi literal 0 HcmV?d00001 diff --git a/src/common/components/sidebar/thumbnails-view.js b/src/common/components/sidebar/thumbnails-view.js index 7173eeb1..74a4bd6c 100644 --- a/src/common/components/sidebar/thumbnails-view.js +++ b/src/common/components/sidebar/thumbnails-view.js @@ -1,10 +1,10 @@ -import React, { Fragment, useState, useCallback, useContext, useEffect, useRef, useImperativeHandle } from 'react'; -import { useIntl } from 'react-intl'; +import React, { Fragment, useState, useCallback, useContext, useEffect, useRef, useImperativeHandle, memo } from 'react'; +import { useIntl, FormattedMessage } from 'react-intl'; import cx from 'classnames'; import { pressedNextKey, pressedPreviousKey } from '../../lib/utilities'; import { ReaderContext } from '../../reader'; -function Thumbnail({ thumbnail, selected, pageLabel, onContextMenu }) { +const Thumbnail = memo(({ thumbnail, selected, pageLabel, onContextMenu }) => { return (
{thumbnail.image - ? - :
+ ? + :
}
{pageLabel}
); -} +}); + +Thumbnail.displayName = 'Thumbnail'; + + function ThumbnailsView(props) { const intl = useIntl(); const [selected, setSelected] = useState([0]); const containerRef = useRef(); + const { onOpenThumbnailContextMenu } = props; const { platform } = useContext(ReaderContext); useEffect(() => { @@ -42,7 +47,7 @@ function ThumbnailsView(props) { useEffect (() => { let options = { - root: containerRef.current.parentNode, + root: containerRef.current, rootMargin: "200px", threshold: 1.0 }; @@ -172,39 +177,63 @@ function ThumbnailsView(props) { } } - function handleContextMenu(event) { + const handleContextMenu = useCallback((event) => { if (platform === 'web') { return; } event.preventDefault(); - props.onOpenThumbnailContextMenu({ + onOpenThumbnailContextMenu({ x: event.clientX, y: event.clientY, pageIndexes: selected }); - } + }, [onOpenThumbnailContextMenu, platform, selected]); + + const handleMoreClick = useCallback((event) => { + event.preventDefault(); + const { x, bottom: y } = event.target.getBoundingClientRect(); + onOpenThumbnailContextMenu({ + x, y, + pageIndexes: selected, + }); + }, [onOpenThumbnailContextMenu, selected]); return ( -
- {props.thumbnails.map((thumbnail, index) => { - let pageLabel = props.pageLabels[index] || (index + 1).toString(); - return ( - + {platform === 'web' && ( +
+ +
+ )} +
+ {props.thumbnails.map((thumbnail, index) => { + let pageLabel = props.pageLabels[index] || (index + 1).toString(); + return ( + + ); + })} +
); } diff --git a/src/common/stylesheets/components/_thumbnails-view.scss b/src/common/stylesheets/components/_thumbnails-view.scss index 6867351f..1ba7fc2e 100644 --- a/src/common/stylesheets/components/_thumbnails-view.scss +++ b/src/common/stylesheets/components/_thumbnails-view.scss @@ -1,13 +1,34 @@ .thumbnails-view { - display: flex; - justify-content: center; - flex-wrap: wrap; - gap: 10px; - padding: 10px 30px 0; - cursor: default; + width: 100%; + height: 100%; user-select: none; - outline: none; + display: flex; + flex-direction: column; + + .thumbnails-header { + display: flex; + position: relative; + margin: $thumbnail-header-padding; + justify-content: space-between; + align-items: center; + + .toolbarButton { + @include icon("more-horizontal", 12px); + } + } + + .thumbnails { + cursor: default; + display: flex; + flex-wrap: wrap; + gap: 10px; + justify-content: center; + outline: none; + overflow: auto; + padding: 10px 30px 0; + user-select: none; + } .thumbnail { .image { @@ -26,6 +47,26 @@ } } + @if $platform =="web" { + position: relative; + .more { + @include icon("more", 12px); + position: absolute; + top: 12px; + right: 12px; + display: none; + cursor: pointer; + + @include state(".thumbnail:hover") { + display: block; + } + + &.active { + display: block; + } + } + } + .label { display: flex; justify-content: center; diff --git a/src/common/stylesheets/themes/_light-darwin.scss b/src/common/stylesheets/themes/_light-darwin.scss index b461e6ad..f38a58d2 100644 --- a/src/common/stylesheets/themes/_light-darwin.scss +++ b/src/common/stylesheets/themes/_light-darwin.scss @@ -258,6 +258,7 @@ $attach-icon-toggled: "darwin/attach-linear-white"; $thumbnail-selection-ring-focus-bg: rgba(0, 0, 0, 0.2); $thumbnail-selection-ring-selected-bg: rgba(0, 0, 0, 0.1); $thumbnail-image-border-color: transparent; +$thumbnail-header-padding: 6px 13px; // Outline & attachment view $sidebar-item-link-btn-color: $text-color; diff --git a/src/en-us.strings.js b/src/en-us.strings.js index d27eab76..5113f65d 100644 --- a/src/en-us.strings.js +++ b/src/en-us.strings.js @@ -145,5 +145,7 @@ export default { 'pdfReader.enterPassword': 'Enter the password to open this PDF file.', 'pdfReader.includeAnnotations': 'Include annotations', 'pdfReader.preparingDocumentForPrinting': 'Preparing document for printing…', - 'pdfReader.phraseNotFound': 'Phrase not found' + 'pdfReader.phraseNotFound': 'Phrase not found', + 'pdfReader.selectedPages': '{count, plural, one {# page} other {# pages}} selected', + 'pdfReader.pageOptions': 'Page Options' };