From b31186db8c19aa0ab2ecf96df9f36618563243a8 Mon Sep 17 00:00:00 2001 From: aria Date: Sun, 15 Dec 2024 12:55:34 -0600 Subject: [PATCH] feat: improve zoom --- .../ImagePickerView/ImagePickerView.tsx | 26 +++++++------- src/client/ImagePickerView/Pagination.tsx | 4 +-- src/constants.ts | 2 +- src/styles.scss | 30 +++++++++++++--- src/utils.ts | 34 +++++++++++++++++++ 5 files changed, 76 insertions(+), 20 deletions(-) diff --git a/src/client/ImagePickerView/ImagePickerView.tsx b/src/client/ImagePickerView/ImagePickerView.tsx index 6bbcfaa..a990c25 100644 --- a/src/client/ImagePickerView/ImagePickerView.tsx +++ b/src/client/ImagePickerView/ImagePickerView.tsx @@ -72,11 +72,18 @@ export const ImagePickerView = () => { const [loadedImages, setLoadedImages] = useState>({}) const [nextImageIndex, setNextImageIndex] = useState(0) - const [rowHeight, setRowHeight] = useState( - (plugin.settings.zoom || DEFAULT_SETTINGS.zoom) * ROW_HEIGHT + const hydratedCSS = useRef(false) + const [zoom, setZoom] = useState( + plugin.settings.zoom || DEFAULT_SETTINGS.zoom ) + const [rowHeight, setRowHeight] = useState(zoom * ROW_HEIGHT) - const [zoom, setZoom] = useState(1) + useEffect(() => { + if (!hydratedCSS.current) { + setGridHeight(zoom) + hydratedCSS.current = true + } + }, [zoom]) const updateZoomSetting = useMemo( () => @@ -182,12 +189,9 @@ export const ImagePickerView = () => { (container: HTMLDivElement) => { const height = container.clientHeight const width = container.clientWidth - - const newRows = Math.floor(height / ROW_HEIGHT) - const newColumns = calculateGrid(gridRef, width, rowHeight) - - setColumns(newColumns) - setItemsPerPage(newRows * newColumns) + const [col, row] = calculateGrid(gridRef, [width, height], rowHeight) + setColumns(col) + setItemsPerPage(col * row) }, [rowHeight] ) @@ -294,13 +298,11 @@ export const ImagePickerView = () => { */ useEffect(() => { if (!isEqual(images, cachedImages.current)) { - console.log('Images changed:', images.length) setLoadedImages({}) setNextImageIndex(0) - setCurrentPage(1) cachedImages.current = images } - }, [images]) + }, [images, totalPages]) return ( <> diff --git a/src/client/ImagePickerView/Pagination.tsx b/src/client/ImagePickerView/Pagination.tsx index 21976de..2498649 100644 --- a/src/client/ImagePickerView/Pagination.tsx +++ b/src/client/ImagePickerView/Pagination.tsx @@ -19,7 +19,7 @@ export const Pagination: FC = ({ onZoom, }) => { return ( -
+
@@ -27,7 +27,7 @@ export const Pagination: FC = ({ type="range" min={MIN_THUMBNAIL_ZOOM} max={MAX_THUMBNAIL_ZOOM} - step={0.1} + step={0.025} value={zoom} onChange={(e) => onZoom(parseFloat(e.target.value))} /> diff --git a/src/constants.ts b/src/constants.ts index 1ca306a..c8b7198 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -55,5 +55,5 @@ export const DEFAULT_SETTINGS: ImagePickerSettings = { * The zoom is applied to the baseline ROW_HEIGHT * to determine the thumbnail size. */ -export const MIN_THUMBNAIL_ZOOM = 0.8 +export const MIN_THUMBNAIL_ZOOM = 0.5 export const MAX_THUMBNAIL_ZOOM = 2 diff --git a/src/styles.scss b/src/styles.scss index 5ec206d..06518ac 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,6 +1,11 @@ $header-height: 60px; $footer-height: 40px; +.image-picker-responsive-container { + width: 100%; + height: 100%; +} + .image-picker-controls { width: 100%; height: $header-height; @@ -25,10 +30,10 @@ $footer-height: 40px; .image-picker-grid { position: relative; + height: 100%; display: grid; grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); grid-gap: 10px; - padding: 0 10px; } .image-picker-item { @@ -39,7 +44,8 @@ $footer-height: 40px; border: 1px solid var(--background-modifier-border); border-radius: 4px; overflow: hidden; - height: 100px; + height: var(--image-picker-grid-height); + min-height: var(--image-picker-grid-height); img { max-width: 100%; @@ -62,20 +68,34 @@ $footer-height: 40px; } } -.image-picker-pagination { +.image-picker-footer { width: 100%; height: $footer-height; display: flex; justify-content: space-between; - padding: 0 0.5rem; align-items: center; flex: 0 0 auto; + margin-top: 1rem; + + > *:first-child { + margin-left: 0; + } + + > *:last-child { + margin-right: 0; + } button { margin: 0 5px; padding: 5px 10px; - font-size: 14px; + font-size: 12px; cursor: pointer; + flex: 0 0 auto; + } + + input[type='range'] { + flex: 1 1 auto; + margin: 0 5px; } } diff --git a/src/utils.ts b/src/utils.ts index 1ae95f1..bc1f73f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -74,3 +74,37 @@ export const nodeToEmbed = ( export const truncate = (text: string, length: number): string => { return text.length > length ? `${text.substring(0, length)}...` : text } + +export const setGridHeight = (zoom: number): void => { + document.documentElement.style.setProperty( + '--image-picker-grid-height', + ROW_HEIGHT * zoom + 'px' + ) +} + +/** + * Returns the number of columns and rows that can fit in the container + * + * The height is always fixed, so we first calculate the rnumber of + * columns that can fit in the container, then calculate the number of + * rows based on the container size and the asset height. + */ +export const calculateGrid = ( + gridRef: React.RefObject, + containerSize: [number, number], + assetHeight: number +): [number, number] => { + if (gridRef.current) { + const [containerWidth, containerHeight] = containerSize + const computedStyle = window.getComputedStyle(gridRef.current) + const gap = parseInt(computedStyle.getPropertyValue('gap'), 10) || 0 + const totalGapsWidth = + containerWidth < assetHeight * 2 + gap + ? 0 + : gap * (Math.floor(containerWidth / assetHeight) - 1) + const columns = Math.floor((containerWidth - totalGapsWidth) / assetHeight) + const rows = Math.floor(containerHeight / (assetHeight + gap)) + return [columns, rows] + } + return [0, 0] +}