mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-04 13:23:28 +00:00
[ENG-1745] Mouse wheel resize (#2366)
* Resize layout items with mouse wheel icon/item size using mouse wheel Update useMouseItemResize.ts Update useMouseItemResize.ts * improve comment * fb * Update useMouseItemResize.ts * Update IconSize.tsx
This commit is contained in:
parent
5624054f1e
commit
f97a761346
|
@ -15,8 +15,8 @@ export const IconSize = () => {
|
||||||
const explorer = useExplorerContext();
|
const explorer = useExplorerContext();
|
||||||
const settings = explorer.useSettingsSnapshot();
|
const settings = explorer.useSettingsSnapshot();
|
||||||
|
|
||||||
const defaultValue = useMemo(
|
const value = useMemo(
|
||||||
() => sizes.findIndex((size) => size[0] === settings.listViewIconSize),
|
() => sizes.indexMap.get(settings.listViewIconSize),
|
||||||
[settings.listViewIconSize]
|
[settings.listViewIconSize]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -25,11 +25,11 @@ export const IconSize = () => {
|
||||||
<Subheading>{t('icon_size')}</Subheading>
|
<Subheading>{t('icon_size')}</Subheading>
|
||||||
<Slider
|
<Slider
|
||||||
step={1}
|
step={1}
|
||||||
max={sizes.length - 1}
|
max={sizes.sizeMap.size - 1}
|
||||||
defaultValue={[defaultValue]}
|
value={[value ?? 0]}
|
||||||
onValueChange={([value]) => {
|
onValueChange={([value]) => {
|
||||||
const size = value !== undefined && sizes[value];
|
const size = value !== undefined && sizes.sizeMap.get(value);
|
||||||
if (size) explorer.settingsStore.listViewIconSize = size[0];
|
if (size) explorer.settingsStore.listViewIconSize = size;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -16,7 +16,7 @@ export const TextSize = () => {
|
||||||
const settings = explorer.useSettingsSnapshot();
|
const settings = explorer.useSettingsSnapshot();
|
||||||
|
|
||||||
const defaultValue = useMemo(
|
const defaultValue = useMemo(
|
||||||
() => sizes.findIndex((size) => size[0] === settings.listViewTextSize),
|
() => sizes.indexMap.get(settings.listViewTextSize),
|
||||||
[settings.listViewTextSize]
|
[settings.listViewTextSize]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -25,11 +25,11 @@ export const TextSize = () => {
|
||||||
<Subheading>{t('text_size')}</Subheading>
|
<Subheading>{t('text_size')}</Subheading>
|
||||||
<Slider
|
<Slider
|
||||||
step={1}
|
step={1}
|
||||||
max={sizes.length - 1}
|
max={sizes.sizeMap.size - 1}
|
||||||
defaultValue={[defaultValue]}
|
defaultValue={[defaultValue ?? 0]}
|
||||||
onValueChange={([value]) => {
|
onValueChange={([value]) => {
|
||||||
const size = value !== undefined && sizes[value];
|
const size = value !== undefined && sizes.sizeMap.get(value);
|
||||||
if (size) explorer.settingsStore.listViewTextSize = size[0];
|
if (size) explorer.settingsStore.listViewTextSize = size;
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,3 +1,18 @@
|
||||||
export function getSizes<T extends { [key: string]: number }>(sizes: T) {
|
export function getSizes<T extends { [key: string]: number }>(sizes: T) {
|
||||||
return (Object.entries(sizes) as [keyof T, T[keyof T]][]).sort((a, b) => a[1] - b[1]);
|
const sizesArr = (Object.entries(sizes) as [keyof T, T[keyof T]][]).sort((a, b) => a[1] - b[1]);
|
||||||
|
|
||||||
|
// Map fo size to index
|
||||||
|
const indexMap = new Map<keyof T, number>();
|
||||||
|
|
||||||
|
// Map of index to size
|
||||||
|
const sizeMap = new Map<number, keyof T>();
|
||||||
|
|
||||||
|
for (let i = 0; i < sizesArr.length; i++) {
|
||||||
|
const size = sizesArr[i];
|
||||||
|
if (!size) continue;
|
||||||
|
indexMap.set(size[0], i);
|
||||||
|
sizeMap.set(i, size[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return { indexMap, sizeMap };
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ export default () => {
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
explorer.settingsStore.gridItemSize = value[0] || 100;
|
explorer.settingsStore.gridItemSize = value[0] || 100;
|
||||||
}}
|
}}
|
||||||
defaultValue={[settings.gridItemSize]}
|
value={[settings.gridItemSize]}
|
||||||
max={200}
|
max={200}
|
||||||
step={10}
|
step={10}
|
||||||
min={60}
|
min={60}
|
||||||
|
|
|
@ -10,7 +10,7 @@ import {
|
||||||
} from '@sd/client';
|
} from '@sd/client';
|
||||||
import { dialogManager } from '@sd/ui';
|
import { dialogManager } from '@sd/ui';
|
||||||
import { Loader } from '~/components';
|
import { Loader } from '~/components';
|
||||||
import { useKeyMatcher, useShortcut } from '~/hooks';
|
import { useKeyMatcher, useMouseItemResize, useShortcut } from '~/hooks';
|
||||||
import { useRoutingContext } from '~/RoutingContext';
|
import { useRoutingContext } from '~/RoutingContext';
|
||||||
import { isNonEmpty } from '~/util';
|
import { isNonEmpty } from '~/util';
|
||||||
|
|
||||||
|
@ -139,6 +139,9 @@ export const View = ({ emptyNotice, ...contextProps }: ExplorerViewProps) => {
|
||||||
return () => element.removeEventListener('wheel', handleWheel);
|
return () => element.removeEventListener('wheel', handleWheel);
|
||||||
}, [explorer.scrollRef, drag?.type]);
|
}, [explorer.scrollRef, drag?.type]);
|
||||||
|
|
||||||
|
// Handle resizing of items in the Explorer grid and list view using the mouse wheel
|
||||||
|
useMouseItemResize();
|
||||||
|
|
||||||
if (!explorer.layouts[layoutMode]) return null;
|
if (!explorer.layouts[layoutMode]) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -18,6 +18,9 @@ export * from './useIsLocationIndexing';
|
||||||
export * from './useIsTextTruncated';
|
export * from './useIsTextTruncated';
|
||||||
export * from './useKeyMatcher';
|
export * from './useKeyMatcher';
|
||||||
export * from './useLocale';
|
export * from './useLocale';
|
||||||
|
export * from './useMouseItemResize';
|
||||||
|
export * from './usePrefersReducedMotion';
|
||||||
|
export * from './useRandomInterval';
|
||||||
export * from './useRedirectToNewLocation';
|
export * from './useRedirectToNewLocation';
|
||||||
export * from './useRouteTitle';
|
export * from './useRouteTitle';
|
||||||
export * from './useShortcut';
|
export * from './useShortcut';
|
||||||
|
@ -25,8 +28,6 @@ export * from './useShowControls';
|
||||||
export * from './useTheme';
|
export * from './useTheme';
|
||||||
export * from './useWindowSize';
|
export * from './useWindowSize';
|
||||||
export * from './useWindowState';
|
export * from './useWindowState';
|
||||||
|
export * from './useZodParams';
|
||||||
export * from './useZodRouteParams';
|
export * from './useZodRouteParams';
|
||||||
export * from './useZodSearchParams';
|
export * from './useZodSearchParams';
|
||||||
export * from './usePrefersReducedMotion';
|
|
||||||
export * from './useRandomInterval';
|
|
||||||
export * from './useZodParams';
|
|
||||||
|
|
65
interface/hooks/useMouseItemResize.ts
Normal file
65
interface/hooks/useMouseItemResize.ts
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
import { useCallback, useEffect } from 'react';
|
||||||
|
import { useExplorerContext } from '~/app/$libraryId/Explorer/Context';
|
||||||
|
import { LIST_VIEW_ICON_SIZES } from '~/app/$libraryId/Explorer/View/ListView/useTable';
|
||||||
|
|
||||||
|
import { useOperatingSystem } from './useOperatingSystem';
|
||||||
|
import { getSizes } from '~/app/$libraryId/Explorer/OptionsPanel/ListView/util';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hook that allows resizing of items in the Explorer views for GRID and LIST only - using the mouse wheel.
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const useMouseItemResize = () => {
|
||||||
|
const os = useOperatingSystem();
|
||||||
|
const explorer = useExplorerContext();
|
||||||
|
const { layoutMode } = explorer.useSettingsSnapshot();
|
||||||
|
|
||||||
|
const handleWheel = useCallback(
|
||||||
|
(e: WheelEvent) => {
|
||||||
|
const isList = layoutMode === 'list';
|
||||||
|
const deltaYModifier = isList ? Math.sign(e.deltaY) : e.deltaY / 10; // Sensitivity adjustment
|
||||||
|
const newSize =
|
||||||
|
Number(
|
||||||
|
isList
|
||||||
|
? explorer.settingsStore.listViewIconSize
|
||||||
|
: explorer.settingsStore.gridItemSize
|
||||||
|
) + deltaYModifier;
|
||||||
|
|
||||||
|
const minSize = isList ? 0 : 60;
|
||||||
|
const maxSize = isList ? 2 : 200;
|
||||||
|
const clampedSize = Math.max(minSize, Math.min(maxSize, newSize));
|
||||||
|
|
||||||
|
if (isList) {
|
||||||
|
const listSizes = getSizes(LIST_VIEW_ICON_SIZES);
|
||||||
|
explorer.settingsStore.listViewIconSize = listSizes.sizeMap.get(clampedSize) ?? "0"
|
||||||
|
} else if (layoutMode === 'grid') {
|
||||||
|
explorer.settingsStore.gridItemSize = Number(clampedSize.toFixed(0));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[explorer.settingsStore, layoutMode]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (os !== 'windows') return;
|
||||||
|
|
||||||
|
const handleKeyDown = (e: KeyboardEvent) => {
|
||||||
|
if (e.key === 'Control') {
|
||||||
|
document.addEventListener('wheel', handleWheel);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyUp = (e: KeyboardEvent) => {
|
||||||
|
if (e.key === 'Control') {
|
||||||
|
document.removeEventListener('wheel', handleWheel);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('keydown', handleKeyDown);
|
||||||
|
document.addEventListener('keyup', handleKeyUp);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('keydown', handleKeyDown);
|
||||||
|
document.removeEventListener('keyup', handleKeyUp);
|
||||||
|
};
|
||||||
|
}, [os, handleWheel]);
|
||||||
|
};
|
Loading…
Reference in a new issue