Skip to content

Commit

Permalink
feat: add thumbnail zoom setting
Browse files Browse the repository at this point in the history
  • Loading branch information
AriTheElk committed Dec 15, 2024
1 parent 921d9f8 commit d768104
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 27 deletions.
1 change: 1 addition & 0 deletions src/ImagePickerSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface ImagePickerSettings {
imageFolder: string
animateGifs: boolean
debugMode: boolean
zoom: number
}

export class ImagePickerSettingTab extends PluginSettingTab {
Expand Down
73 changes: 49 additions & 24 deletions src/client/ImagePickerView/ImagePickerView.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { debounce, isEqual, truncate } from 'lodash'
import { debounce, isEqual, throttle, truncate } from 'lodash'
import { useEffect, useState, useRef, useCallback, useMemo } from 'react'
import { Notice, TFile } from 'obsidian'

Expand All @@ -7,8 +7,15 @@ import {
MOBILE_MAX_FILE_SIZE,
DESKTOP_MAX_FILE_SIZE,
ROW_HEIGHT,
DEFAULT_SETTINGS,
} from '../../constants'
import { copyToClipboard, getSizeInKb, nodeToEmbed } from '../../utils'
import {
calculateGrid,
copyToClipboard,
getSizeInKb,
nodeToEmbed,
setGridHeight,
} from '../../utils'
import { AbstractIndexerNode, IndexerNode } from '../../backend/Indexer'
import { useApp, useFiles, usePlugin } from '../ImagePickerContext'

Expand Down Expand Up @@ -49,7 +56,6 @@ export const ImagePickerView = () => {
const app = useApp()
const images = useFiles()
const cachedImages = useRef<IndexerNode[]>([])
const [searchInput, setSearchInput] = useState('')
const [searchQuery, setSearchQuery] = useState<
ReturnType<typeof tokenizeSearchQuery>
>({
Expand All @@ -66,6 +72,42 @@ export const ImagePickerView = () => {
const [loadedImages, setLoadedImages] = useState<Record<string, string>>({})
const [nextImageIndex, setNextImageIndex] = useState(0)

const [rowHeight, setRowHeight] = useState(
(plugin.settings.zoom || DEFAULT_SETTINGS.zoom) * ROW_HEIGHT
)

const [zoom, setZoom] = useState(1)

const updateZoomSetting = useMemo(
() =>
debounce((zoom: number) => {
plugin.settings.zoom = zoom
plugin.backgrounder.enqueue({
type: 'saveSettings',
disableDoubleQueue: true,
action: plugin.saveSettings,
})
}, 500),
[plugin.backgrounder, plugin.saveSettings, plugin.settings]
)

const updateVisualZoom = useCallback(
throttle((zoom: number) => {
setGridHeight(zoom)
setRowHeight(zoom * ROW_HEIGHT)
}, 50),
[]
)

const onZoom = useCallback(
(zoom: number) => {
setZoom(zoom)
updateZoomSetting(zoom)
updateVisualZoom(zoom)
},
[updateVisualZoom, updateZoomSetting]
)

useEffect(() => {
if (columns !== prevColumns.current) {
setLoadedImages({})
Expand Down Expand Up @@ -136,37 +178,18 @@ export const ImagePickerView = () => {
.sort((a, b) => b.stat.ctime - a.stat.ctime)
}, [images, app.vault, searchQuery])

const calculateGrid = useCallback(
(containerSize: number, assetSize: number) => {
if (gridRef.current) {
const computedStyle = window.getComputedStyle(gridRef.current)
const gap = parseInt(computedStyle.getPropertyValue('gap'), 10) || 0
const totalGapsWidth =
containerSize < assetSize * 2 + gap
? 0
: gap * (Math.floor(containerSize / assetSize) - 1)
const newColumns = Math.floor(
(containerSize - totalGapsWidth) / assetSize
)
return newColumns
}
return 0
},
[]
)

const updateCalculations = useCallback(
(container: HTMLDivElement) => {
const height = container.clientHeight
const width = container.clientWidth

const newRows = Math.floor(height / ROW_HEIGHT)
const newColumns = calculateGrid(width, 100)
const newColumns = calculateGrid(gridRef, width, rowHeight)

setColumns(newColumns)
setItemsPerPage(newRows * newColumns)
},
[calculateGrid]
[rowHeight]
)

useEffect(() => {
Expand Down Expand Up @@ -354,6 +377,8 @@ export const ImagePickerView = () => {
current={currentPage}
onNext={handleNextPage}
onPrev={handlePrevPage}
zoom={zoom}
onZoom={onZoom}
/>
</>
)
Expand Down
16 changes: 13 additions & 3 deletions src/client/ImagePickerView/Pagination.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,36 @@
import React, { FC } from 'react'
import { MAX_THUMBNAIL_ZOOM, MIN_THUMBNAIL_ZOOM } from 'src/constants'

interface PaginationProps {
total: number
current: number
zoom: number
onNext: () => void
onPrev: () => void
onZoom: (zoom: number) => void
}

export const Pagination: FC<PaginationProps> = ({
total,
current,
onNext,
onPrev,
zoom,
onZoom,
}) => {
return (
<div className="image-picker-pagination">
<button onClick={onPrev} disabled={current === 1}>
Previous
</button>
<span>
Page {current} of {total || 1}
</span>
<input
type="range"
min={MIN_THUMBNAIL_ZOOM}
max={MAX_THUMBNAIL_ZOOM}
step={0.1}
value={zoom}
onChange={(e) => onZoom(parseFloat(e.target.value))}
/>
<button onClick={onNext} disabled={current === total}>
Next
</button>
Expand Down
10 changes: 10 additions & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,14 @@ export const DEFAULT_SETTINGS: ImagePickerSettings = {
imageFolder: '',
animateGifs: false,
debugMode: false,
zoom: 1,
}

/**
* The min/max thumbnail zoom for the image picker
*
* The zoom is applied to the baseline ROW_HEIGHT
* to determine the thumbnail size.
*/
export const MIN_THUMBNAIL_ZOOM = 0.8
export const MAX_THUMBNAIL_ZOOM = 2

0 comments on commit d768104

Please sign in to comment.