[ENG-1142] Path bar shortcut (#1377)

* Path bar shortcut

* Add option to popover and tweak UI

* increase size of folder icon + frame thumbs

* view adjustments

* truncate

---------

Co-authored-by: nikec <nikec.job@gmail.com>
This commit is contained in:
ameer2468
2023-09-27 17:49:01 +03:00
committed by GitHub
parent 8441927d81
commit fab88de8bf
14 changed files with 223 additions and 101 deletions

View File

@@ -42,6 +42,7 @@ export interface ThumbProps {
mediaControls?: boolean;
pauseVideo?: boolean;
className?: string;
frameClassName?: string;
childClassName?: string | ((type: ThumbType | `${ThumbType}`) => string | undefined);
}
@@ -62,6 +63,7 @@ export const FileThumb = memo((props: ThumbProps) => {
const childClassName = 'max-h-full max-w-full object-contain';
const frameClassName = clsx(
'rounded-sm border-2 border-app-line bg-app-darkBox',
props.frameClassName,
isDark ? classes.checkers : classes.checkersLight
);

View File

@@ -1,4 +1,5 @@
import { RadixCheckbox, Select, SelectOption, Slider, tw, z } from '@sd/ui';
import { getExplorerLayoutStore, useExplorerLayoutStore } from '~/../packages/client/src';
import { SortOrderSchema } from '~/app/route-schemas';
import { useExplorerContext } from './Context';
@@ -15,6 +16,7 @@ const Subheading = tw.div`text-ink-dull mb-1 text-xs font-medium`;
export default () => {
const explorerStore = useExplorerStore();
const explorer = useExplorerContext();
const layoutStore = useExplorerLayoutStore();
const settings = explorer.useSettingsSnapshot();
@@ -117,44 +119,58 @@ export default () => {
</div>
)}
<div className="flex flex-col gap-2">
{settings.layoutMode === 'grid' && (
<div>
<Subheading>Explorer</Subheading>
<div className="flex flex-row flex-wrap justify-between gap-1">
<RadixCheckbox
checked={settings.showBytesInGridView}
label="Show Object size"
name="showBytesInGridView"
checked={layoutStore.showPathBar}
label="Show Path Bar"
name="showPathBar"
onCheckedChange={(value) => {
if (typeof value !== 'boolean') return;
getExplorerLayoutStore().showPathBar = value;
}}
/>
{settings.layoutMode === 'grid' && (
<RadixCheckbox
checked={settings.showBytesInGridView}
label="Show Object size"
name="showBytesInGridView"
onCheckedChange={(value) => {
if (typeof value !== 'boolean') return;
explorer.settingsStore.showBytesInGridView = value;
}}
/>
)}
<RadixCheckbox
checked={settings.showHiddenFiles}
label="Show Hidden Files"
name="showHiddenFiles"
onCheckedChange={(value) => {
if (typeof value !== 'boolean') return;
explorer.settingsStore.showBytesInGridView = value;
explorer.settingsStore.showHiddenFiles = value;
}}
/>
)}
<RadixCheckbox
checked={settings.showHiddenFiles}
label="Show Hidden Files"
name="showHiddenFiles"
onCheckedChange={(value) => {
if (typeof value !== 'boolean') return;
{settings.layoutMode === 'media' && (
<RadixCheckbox
checked={settings.mediaAspectSquare}
label="Show square thumbnails"
name="mediaAspectSquare"
onCheckedChange={(value) => {
if (typeof value !== 'boolean') return;
explorer.settingsStore.showHiddenFiles = value;
}}
/>
explorer.settingsStore.mediaAspectSquare = value;
}}
/>
)}
</div>
</div>
{settings.layoutMode === 'media' && (
<RadixCheckbox
checked={settings.mediaAspectSquare}
label="Show square thumbnails"
name="mediaAspectSquare"
onCheckedChange={(value) => {
if (typeof value !== 'boolean') return;
explorer.settingsStore.mediaAspectSquare = value;
}}
/>
)}
<div>
<Subheading>Double click action</Subheading>
<Select

View File

@@ -3,14 +3,16 @@ import { getIcon } from '@sd/assets/util';
import clsx from 'clsx';
import { memo, useCallback, useEffect, useState } from 'react';
import { useLocation } from 'react-router';
import { ExplorerItem } from '@sd/client';
import { ExplorerItem, getExplorerLayoutStore, useExplorerLayoutStore } from '@sd/client';
import { SearchParamsSchema } from '~/app/route-schemas';
import { useIsDark, useZodSearchParams } from '~/hooks';
import { useIsDark, useKeyBind, useKeyMatcher, useZodSearchParams } from '~/hooks';
import { useExplorerContext } from '../Context';
import { FileThumb } from '../FilePath/Thumb';
import { useExplorerSearchParams } from '../util';
export const PATH_BAR_HEIGHT = 32;
export const ExplorerPath = memo(() => {
const location = useLocation();
const isDark = useIsDark();
@@ -18,6 +20,8 @@ export const ExplorerPath = memo(() => {
const [data, setData] = useState<{ kind: string; name: string }[] | null>(null);
const [selectedItem, setSelectedItem] = useState<ExplorerItem | undefined>(undefined);
const metaCtrlKey = useKeyMatcher('Meta').key;
const layoutStore = useExplorerLayoutStore();
const explorerContext = useExplorerContext();
const [{ path }] = useExplorerSearchParams();
@@ -79,10 +83,17 @@ export const ExplorerPath = memo(() => {
} else setSelectedItem(undefined);
}, [pathInfo, explorerContext.selectedItems, formatPathData]);
useKeyBind([metaCtrlKey, 'p'], (e) => {
e.stopPropagation();
getExplorerLayoutStore().showPathBar = !layoutStore.showPathBar;
});
if (!layoutStore.showPathBar) return null;
return (
<div
className="fixed bottom-0 flex h-8 w-full items-center gap-1 border-t
border-t-app-line bg-app/90 px-3.5 text-[11px] text-ink-faint backdrop-blur-lg"
className="absolute inset-x-0 bottom-0 flex items-center gap-1 border-t border-t-app-line bg-app/90 px-3.5 text-[11px] text-ink-faint backdrop-blur-lg"
style={{ height: PATH_BAR_HEIGHT }}
>
{data?.map((p, index) => {
return (
@@ -94,8 +105,8 @@ export const ExplorerPath = memo(() => {
index !== data.length - 1 && ' cursor-pointer hover:brightness-125'
)}
>
<img src={getIcon('Folder', isDark)} alt="folder" className="h-3 w-3" />
<p className="truncate">{p.name}</p>
<img src={getIcon('Folder', isDark)} alt="folder" className="h-4 w-4" />
<span className="max-w-xs truncate">{p.name}</span>
{index !== (data?.length as number) - 1 && (
<CaretRight weight="bold" size={10} />
)}
@@ -105,8 +116,10 @@ export const ExplorerPath = memo(() => {
{selectedItem && (
<div className="pointer-events-none flex items-center gap-1">
{data && data.length > 0 && <CaretRight weight="bold" size={10} />}
<FileThumb size={12} data={selectedItem} />
{'name' in selectedItem.item && <p>{selectedItem.item.name}</p>}
<FileThumb size={16} frame frameClassName="!border" data={selectedItem} />
{'name' in selectedItem.item && (
<span className="max-w-xs truncate">{selectedItem.item.name}</span>
)}
</div>
)}
</div>

View File

@@ -123,6 +123,8 @@ export default ({ children }: { children: RenderItem }) => {
const itemDetailsHeight = settings.gridItemSize / 4 + (settings.showBytesInGridView ? 20 : 0);
const itemHeight = settings.gridItemSize + itemDetailsHeight;
const padding = settings.layoutMode === 'grid' ? 12 : 0;
const grid = useGridList({
ref: explorerView.ref,
count: explorer.items?.length ?? 0,
@@ -142,7 +144,14 @@ export default ({ children }: { children: RenderItem }) => {
[explorer.items]
),
getItemData: useCallback((index: number) => explorer.items?.[index], [explorer.items]),
padding: explorerView.padding ?? settings.layoutMode === 'grid' ? 12 : undefined,
padding: {
...explorerView.padding,
bottom: explorerView.bottom
? (explorerView.padding?.bottom ?? padding) + explorerView.bottom
: undefined,
x: padding,
y: padding
},
gap:
explorerView.gap ||
(settings.layoutMode === 'grid' ? explorerStore.gridGap : undefined),
@@ -326,8 +335,6 @@ export default ({ children }: { children: RenderItem }) => {
explorerView.ref.current &&
(e.key === 'ArrowUp' || e.key === 'ArrowDown')
) {
const paddingTop = parseInt(getComputedStyle(explorer.scrollRef.current).paddingTop);
const viewRect = explorerView.ref.current.getBoundingClientRect();
const itemRect = newSelectedItem.rect;
@@ -335,7 +342,9 @@ export default ({ children }: { children: RenderItem }) => {
const itemBottom = itemRect.bottom + viewRect.top;
const scrollRect = explorer.scrollRef.current.getBoundingClientRect();
const scrollTop = paddingTop + (explorerView.top || 0) + 1;
const scrollTop =
(explorerView.top ??
parseInt(getComputedStyle(explorer.scrollRef.current).paddingTop)) + 1;
const scrollBottom = scrollRect.height - (os !== 'windows' && os !== 'browser' ? 2 : 1);
if (itemTop < scrollTop) {
@@ -343,17 +352,18 @@ export default ({ children }: { children: RenderItem }) => {
top:
itemTop -
scrollTop -
(newSelectedItem.row === 0 ? grid.padding.y : 0) -
(newSelectedItem.row !== 0 ? grid.gap.y / 2 : 0),
(newSelectedItem.row === 0 ? grid.padding.top : grid.gap.y / 2),
behavior: 'smooth'
});
} else if (itemBottom > scrollBottom) {
} else if (itemBottom > scrollBottom - (explorerView.bottom ?? 0)) {
explorer.scrollRef.current.scrollBy({
top:
itemBottom -
scrollBottom +
(newSelectedItem.row === grid.rowCount - 1 ? grid.padding.y : 0) +
(newSelectedItem.row !== grid.rowCount - 1 ? grid.gap.y / 2 : 0),
(explorerView.bottom ?? 0) +
(newSelectedItem.row === grid.rowCount - 1
? grid.padding.bottom
: grid.gap.y / 2),
behavior: 'smooth'
});
}

View File

@@ -28,13 +28,15 @@ import {
} from '../../store';
import { uniqueId } from '../../util';
import { useExplorerViewContext } from '../../ViewContext';
import { useExplorerViewPadding } from '../util';
import { ViewItem } from '../ViewItem';
import { getRangeDirection, Range, useRanges } from './util/ranges';
import { useTable } from './util/table';
interface ListViewItemProps {
row: Row<ExplorerItem>;
paddingX: number;
paddingLeft: number;
paddingRight: number;
// Props below are passed to trigger a rerender
// TODO: Find a better solution
columnSizing: ColumnSizingState;
@@ -48,7 +50,7 @@ const ListViewItem = memo((props: ListViewItemProps) => {
<ViewItem
data={props.row.original}
className="relative flex h-full items-center"
style={{ paddingLeft: props.paddingX, paddingRight: props.paddingX }}
style={{ paddingLeft: props.paddingLeft, paddingRight: props.paddingRight }}
>
{props.row.getVisibleCells().map((cell) => (
<div
@@ -86,6 +88,8 @@ const HeaderColumnName = ({ name }: { name: string }) => {
};
const ROW_HEIGHT = 45;
const PADDING_X = 16;
const PADDING_Y = 12;
export default () => {
const layout = useLayoutContext();
@@ -115,17 +119,21 @@ export default () => {
rows: rowsById
});
const viewPadding = useExplorerViewPadding(explorerView.padding);
const padding = {
x: explorerView.padding?.x ?? 16,
y: explorerView.padding?.y ?? 12
top: viewPadding.top ?? PADDING_Y,
bottom: viewPadding.bottom ?? PADDING_Y,
left: viewPadding.left ?? PADDING_X,
right: viewPadding.right ?? PADDING_X
};
const rowVirtualizer = useVirtualizer({
count: explorer.count ?? rows.length,
getScrollElement: useCallback(() => explorer.scrollRef.current, [explorer.scrollRef]),
estimateSize: useCallback(() => ROW_HEIGHT, []),
paddingStart: padding.y,
paddingEnd: padding.y,
paddingStart: padding.top,
paddingEnd: padding.bottom + (explorerView.bottom ?? 0),
scrollMargin: listOffset,
overscan: explorer.overscan ?? 10
});
@@ -442,7 +450,8 @@ export default () => {
);
const tableWidth = tableRef.current.offsetWidth;
const columnsWidth = Object.values(sizing).reduce((a, b) => a + b, 0) + padding.x * 2;
const columnsWidth =
Object.values(sizing).reduce((a, b) => a + b, 0) + (padding.left + padding.right);
if (columnsWidth < tableWidth) {
const nameWidth = (sizing.name ?? 0) + (tableWidth - columnsWidth);
@@ -463,7 +472,7 @@ export default () => {
}
setSized(true);
}, [columnSizing, columnVisibility, padding.x, sized, table]);
}, [columnSizing, columnVisibility, padding.left, padding.right, sized, table]);
// Load more items
useEffect(() => {
@@ -671,37 +680,36 @@ export default () => {
}
} else explorer.resetSelectedItems([item]);
if (explorer.scrollRef.current) {
const tableBodyRect = tableBodyRef.current?.getBoundingClientRect();
if (explorer.scrollRef.current && tableBodyRef.current) {
const scrollRect = explorer.scrollRef.current.getBoundingClientRect();
const paddingTop = parseInt(getComputedStyle(explorer.scrollRef.current).paddingTop);
const top =
(explorerView.top ? paddingTop + explorerView.top : paddingTop) +
const tableTop =
scrollRect.top +
(explorer.scrollRef.current.scrollTop > listOffset ? 36 : 0);
(explorerView.top ??
parseInt(getComputedStyle(explorer.scrollRef.current).paddingTop)) +
(explorer.scrollRef.current.scrollTop > top ? 36 : 0);
const rowTop =
scrollRect.top +
nextRow.index * ROW_HEIGHT +
rowVirtualizer.options.paddingStart +
(tableBodyRect?.top || 0) +
scrollRect.top;
tableBodyRef.current.getBoundingClientRect().top;
const rowBottom = rowTop + ROW_HEIGHT;
if (rowTop < top) {
const scrollBy = rowTop - top - (nextRow.index === 0 ? padding.y : 0);
if (rowTop < tableTop) {
const scrollBy = rowTop - tableTop - (nextRow.index === 0 ? padding.top : 0);
explorer.scrollRef.current.scrollBy({
top: scrollBy,
behavior: 'smooth'
});
} else if (rowBottom > scrollRect.bottom) {
} else if (rowBottom > scrollRect.height - (explorerView.bottom ?? 0)) {
const scrollBy =
rowBottom -
scrollRect.height +
(nextRow.index === rows.length - 1 ? padding.y : 0);
(explorerView.bottom ?? 0) +
(nextRow.index === rows.length - 1 ? padding.bottom : 0);
explorer.scrollRef.current.scrollBy({
top: scrollBy,
@@ -735,7 +743,8 @@ export default () => {
{} as ColumnSizingState
);
const columnsWidth = Object.values(sizing).reduce((a, b) => a + b, 0) + padding.x * 2;
const columnsWidth =
Object.values(sizing).reduce((a, b) => a + b, 0) + (padding.left + padding.right);
if (locked) {
const newNameSize = (sizing.name ?? 0) + (width - columnsWidth);
@@ -830,7 +839,8 @@ export default () => {
width:
i === 0 ||
i === headerGroup.headers.length - 1
? size + padding.x
? size +
padding[i ? 'right' : 'left']
: size
}}
onClick={() => {
@@ -966,7 +976,10 @@ export default () => {
selectedNext &&
'rounded-b-none border-b-0 border-b-transparent'
)}
style={{ right: padding.x, left: padding.x }}
style={{
right: padding.right,
left: padding.left
}}
>
{selectedPrior && (
<div className="absolute inset-x-3 top-0 h-px bg-accent/10" />
@@ -975,7 +988,8 @@ export default () => {
<ListViewItem
row={row}
paddingX={padding.x}
paddingLeft={padding.left}
paddingRight={padding.right}
columnSizing={columnSizing}
columnVisibility={columnVisibility}
isCut={cut}

View File

@@ -25,12 +25,21 @@ import { useQuickPreviewContext } from '../QuickPreview/Context';
import { useQuickPreviewStore } from '../QuickPreview/store';
import { getExplorerStore } from '../store';
import { ViewContext, type ExplorerViewContext } from '../ViewContext';
import { ExplorerPath } from './ExplorerPath';
import GridView from './GridView';
import ListView from './ListView';
import MediaView from './MediaView';
import { useExplorerViewPadding } from './util';
import { useViewItemDoubleClick } from './ViewItem';
export interface ExplorerViewPadding {
x?: number;
y?: number;
top?: number;
bottom?: number;
left?: number;
right?: number;
}
export interface ExplorerViewProps
extends Omit<
ExplorerViewContext,
@@ -39,7 +48,7 @@ export interface ExplorerViewProps
className?: string;
style?: React.CSSProperties;
emptyNotice?: JSX.Element;
padding?: number | { x?: number; y?: number };
padding?: number | ExplorerViewPadding;
}
export default memo(
@@ -60,6 +69,8 @@ export default memo(
const [isRenaming, setIsRenaming] = useState(false);
const [showLoading, setShowLoading] = useState(false);
const viewPadding = useExplorerViewPadding(padding);
useKeyDownHandlers({
disabled: isRenaming || quickPreviewStore.open
});
@@ -101,10 +112,7 @@ export default memo(
isRenaming,
setIsRenaming,
ref,
padding: {
x: typeof padding === 'object' ? padding.x : padding,
y: typeof padding === 'object' ? padding.y : padding
}
padding: viewPadding
}}
>
{layoutMode === 'grid' && <GridView />}
@@ -117,7 +125,6 @@ export default memo(
) : (
emptyNotice
)}
<ExplorerPath />
</div>
{quickPreview.ref && createPortal(<QuickPreview />, quickPreview.ref)}

View File

@@ -0,0 +1,17 @@
import { useCallback } from 'react';
import { ExplorerViewPadding } from '.';
export const useExplorerViewPadding = (padding?: number | ExplorerViewPadding) => {
const getPadding = useCallback(
(key: keyof ExplorerViewPadding) => (typeof padding === 'object' ? padding[key] : padding),
[padding]
);
return {
top: getPadding('top') ?? getPadding('y'),
bottom: getPadding('bottom') ?? getPadding('y'),
left: getPadding('left') ?? getPadding('x'),
right: getPadding('right') ?? getPadding('x')
};
};

View File

@@ -1,13 +1,16 @@
import { createContext, useContext, type ReactNode, type RefObject } from 'react';
import { ExplorerViewPadding } from './View';
export interface ExplorerViewContext {
ref: RefObject<HTMLDivElement>;
top?: number;
bottom?: number;
contextMenu?: ReactNode;
setIsContextMenuOpen?: (isOpen: boolean) => void;
isRenaming: boolean;
setIsRenaming: (isRenaming: boolean) => void;
padding?: { x?: number; y?: number };
padding?: Omit<ExplorerViewPadding, 'x' | 'y'>;
gap?: number | { x?: number; y?: number };
selectable: boolean;
listViewOptions?: {

View File

@@ -1,6 +1,6 @@
import { FolderNotchOpen } from '@phosphor-icons/react';
import { useEffect, type PropsWithChildren, type ReactNode } from 'react';
import { useLibrarySubscription } from '@sd/client';
import { CSSProperties, type PropsWithChildren, type ReactNode } from 'react';
import { useExplorerLayoutStore, useLibrarySubscription } from '@sd/client';
import { TOP_BAR_HEIGHT } from '../TopBar';
import { useExplorerContext } from './Context';
@@ -9,8 +9,8 @@ import DismissibleNotice from './DismissibleNotice';
import { Inspector, INSPECTOR_WIDTH } from './Inspector';
import ExplorerContextMenu from './ParentContextMenu';
import { useExplorerStore } from './store';
import { useExplorerSearchParams } from './util';
import View, { EmptyNotice, ExplorerViewProps } from './View';
import { ExplorerPath, PATH_BAR_HEIGHT } from './View/ExplorerPath';
interface Props {
emptyNotice?: ExplorerViewProps['emptyNotice'];
@@ -24,6 +24,7 @@ interface Props {
export default function Explorer(props: PropsWithChildren<Props>) {
const explorerStore = useExplorerStore();
const explorer = useExplorerContext();
const { showPathBar } = useExplorerLayoutStore();
// Can we put this somewhere else -_-
useLibrarySubscription(['jobs.newThumbnail'], {
@@ -45,10 +46,16 @@ export default function Explorer(props: PropsWithChildren<Props>) {
<div
ref={explorer.scrollRef}
className="custom-scroll explorer-scroll h-screen overflow-x-hidden"
style={{
paddingTop: TOP_BAR_HEIGHT,
paddingRight: explorerStore.showInspector ? INSPECTOR_WIDTH : 0
}}
style={
{
'--scrollbar-margin-top': `${TOP_BAR_HEIGHT}px`,
'--scrollbar-margin-bottom': `${
showPathBar ? PATH_BAR_HEIGHT + 2 : 0 // TODO: Fix for web app
}px`,
'paddingTop': TOP_BAR_HEIGHT,
'paddingRight': explorerStore.showInspector ? INSPECTOR_WIDTH : 0
} as CSSProperties
}
>
{explorer.items && explorer.items.length > 0 && <DismissibleNotice />}
@@ -63,15 +70,21 @@ export default function Explorer(props: PropsWithChildren<Props>) {
)
}
listViewOptions={{ hideHeaderBorder: true }}
bottom={showPathBar ? PATH_BAR_HEIGHT : undefined}
/>
</div>
</div>
</ExplorerContextMenu>
<ExplorerPath />
{explorerStore.showInspector && (
<Inspector
className="no-scrollbar absolute inset-y-0 right-1.5 pb-3 pl-3 pr-1.5"
style={{ paddingTop: TOP_BAR_HEIGHT + 12 }}
className="no-scrollbar absolute right-1.5 top-0 pb-3 pl-3 pr-1.5"
style={{
paddingTop: TOP_BAR_HEIGHT + 12,
bottom: showPathBar ? PATH_BAR_HEIGHT : 0
}}
/>
)}
</>

View File

@@ -69,6 +69,10 @@ const shortcutCategories: Record<string, Shortcut[]> = {
action: 'Show inspector',
key: [[[ModifierKeys.Control], ['i']]]
},
{
action: 'Show path bar',
key: [[[ModifierKeys.Control], ['p']]]
},
{
action: 'Rename file or folder',
key: [[[], ['Enter']]]

View File

@@ -101,7 +101,9 @@ body {
width: 6px;
}
&::-webkit-scrollbar-track {
@apply mt-[46px] rounded-[6px] bg-transparent;
@apply rounded-[6px] bg-transparent;
margin-top: var(--scrollbar-margin-top);
margin-bottom: var(--scrollbar-margin-bottom);
}
&::-webkit-scrollbar-thumb {
@apply rounded-[6px] bg-app-explorerScrollbar;

View File

@@ -11,6 +11,8 @@ import React, {
} from 'react';
import { useMutationObserver } from 'rooks';
import useResizeObserver from 'use-resize-observer';
import { ExplorerViewPadding } from '~/app/$libraryId/Explorer/View';
import { useExplorerViewPadding } from '~/app/$libraryId/Explorer/View/util';
type ItemData = any | undefined;
type ItemId = number | string;
@@ -28,7 +30,7 @@ export interface UseGridListProps<IdT extends ItemId = number, DataT extends Ite
count: number;
totalCount?: number;
ref: RefObject<HTMLElement>;
padding?: number | { x?: number; y?: number };
padding?: number | ExplorerViewPadding;
gap?: number | { x?: number; y?: number };
overscan?: number;
top?: number;
@@ -53,8 +55,12 @@ export const useGridList = <IdT extends ItemId = number, DataT extends ItemData
const count = props.totalCount ?? props.count;
const paddingX = (typeof padding === 'object' ? padding.x : padding) || 0;
const paddingY = (typeof padding === 'object' ? padding.y : padding) || 0;
const gridPadding = useExplorerViewPadding(padding);
const paddingTop = gridPadding.top ?? 0;
const paddingBottom = gridPadding.bottom ?? 0;
const paddingLeft = gridPadding.left ?? 0;
const paddingRight = gridPadding.right ?? 0;
const gapX = (typeof gap === 'object' ? gap.x : gap) || 0;
const gapY = (typeof gap === 'object' ? gap.y : gap) || 0;
@@ -62,7 +68,7 @@ export const useGridList = <IdT extends ItemId = number, DataT extends ItemData
const itemWidth = size ? (typeof size === 'object' ? size.width : size) : undefined;
const itemHeight = size ? (typeof size === 'object' ? size.height : size) : undefined;
const gridWidth = width ? width - (paddingX || 0) * 2 : 0;
const gridWidth = width ? width - (paddingLeft + paddingRight) : 0;
let columnCount = columns || 0;
@@ -91,8 +97,8 @@ export const useGridList = <IdT extends ItemId = number, DataT extends ItemData
const column = index % columnCount;
const row = Math.floor(index / columnCount);
const x = paddingX + (column !== 0 ? gapX : 0) * column + virtualItemWidth * column;
const y = paddingY + (row !== 0 ? gapY : 0) * row + virtualItemHeight * row;
const x = paddingLeft + (column !== 0 ? gapX : 0) * column + virtualItemWidth * column;
const y = paddingTop + (row !== 0 ? gapY : 0) * row + virtualItemHeight * row;
const item: GridListItem<typeof id, DataT> = {
index,
@@ -121,8 +127,8 @@ export const useGridList = <IdT extends ItemId = number, DataT extends ItemData
gapY,
getItemId,
getItemData,
paddingX,
paddingY,
paddingLeft,
paddingTop,
virtualItemHeight,
virtualItemWidth
]
@@ -133,7 +139,7 @@ export const useGridList = <IdT extends ItemId = number, DataT extends ItemData
rowCount,
totalRowCount,
width: gridWidth,
padding: { x: paddingX, y: paddingY },
padding: { top: paddingTop, bottom: paddingBottom, left: paddingLeft, right: paddingRight },
gap: { x: gapX, y: gapY },
itemHeight,
itemWidth,
@@ -169,8 +175,8 @@ export const GridList = ({ grid, children, scrollRef }: GridListProps) => {
count: grid.totalRowCount,
getScrollElement: () => scrollRef.current,
estimateSize: getHeight,
paddingStart: grid.padding.y,
paddingEnd: grid.padding.y,
paddingStart: grid.padding.top,
paddingEnd: grid.padding.bottom,
overscan: grid.overscan,
scrollMargin: listOffset
});
@@ -180,8 +186,8 @@ export const GridList = ({ grid, children, scrollRef }: GridListProps) => {
count: grid.columnCount,
getScrollElement: () => scrollRef.current,
estimateSize: getWidth,
paddingStart: grid.padding.x,
paddingEnd: grid.padding.x
paddingStart: grid.padding.left,
paddingEnd: grid.padding.right
});
const virtualRows = rowVirtualizer.getVirtualItems();

View File

@@ -11,3 +11,4 @@ export * from './useThemeStore';
export * from './useNotifications';
export * from './useForceUpdate';
export * from './useUnitFormatStore';
export * from './useExplorerLayoutStore';

View File

@@ -0,0 +1,14 @@
import { valtioPersist } from "../lib";
import { useSnapshot } from 'valtio';
const explorerLayoutStore = valtioPersist('sd-explorer-layout', {
showPathBar: true,
})
export function useExplorerLayoutStore() {
return useSnapshot(explorerLayoutStore);
}
export function getExplorerLayoutStore() {
return explorerLayoutStore;
}