feat: Add an icon size slider component and implement dynamic icon sizing for document views, while refactoring the documents panel layout.

This commit is contained in:
2025-12-01 23:42:43 +01:00
parent 033026f57c
commit 601ced5981
3 changed files with 66 additions and 16 deletions
@@ -0,0 +1,31 @@
import React from 'react';
interface IconSizeSliderProps {
scale: number;
onChange: (scale: number) => void;
min?: number;
max?: number;
}
const IconSizeSlider: React.FC<IconSizeSliderProps> = ({
scale,
onChange,
min = 0.5,
max = 2,
}) => {
return (
<div className="icon-size-slider">
<input
type="range"
className="icon-size-slider__input"
min={min}
max={max}
step="any"
value={scale}
onChange={(e) => onChange(parseFloat(e.target.value))}
/>
</div>
);
};
export default IconSizeSlider;
@@ -1,4 +1,10 @@
import React, { useCallback, useEffect, useMemo, useRef } from 'react'; import React, {
useCallback,
useMemo,
useState,
useRef,
useEffect,
} from 'react';
import { DocumentsList, DocumentsGrid } from '../DocumentsView'; import { DocumentsList, DocumentsGrid } from '../DocumentsView';
import type { DragEvent, ReactNode, RefObject } from 'react'; import type { DragEvent, ReactNode, RefObject } from 'react';
import type { import type {
@@ -162,7 +168,6 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
const showingSearchResults = Array.isArray(searchResultIds); const showingSearchResults = Array.isArray(searchResultIds);
const rows = showingSearchResults && searchDocuments ? searchDocuments : documents; const rows = showingSearchResults && searchDocuments ? searchDocuments : documents;
const searchResultCount = Array.isArray(searchResultIds) ? searchResultIds.length : 0;
const viewId = useMemo(() => { const viewId = useMemo(() => {
if (showingSearchResults) { if (showingSearchResults) {
@@ -185,9 +190,7 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
const headerTitle = showingSearchResults const headerTitle = showingSearchResults
? 'Search results' ? 'Search results'
: currentFolderName || 'Documents'; : currentFolderName || 'Documents';
const headerSubtitle = showingSearchResults const headerSubtitle = null;
? `${searchResultCount} matching document${searchResultCount === 1 ? '' : 's'}`
: null;
const headerActions = useMemo( const headerActions = useMemo(
() => createDocumentsTableHeaderActions({ () => createDocumentsTableHeaderActions({
viewMode, viewMode,
@@ -320,7 +323,6 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
const suppressDocumentClickRef = useRef(false); const suppressDocumentClickRef = useRef(false);
const isGridView = viewMode === 'grid'; const isGridView = viewMode === 'grid';
const isDeskView = viewMode === 'desk'; const isDeskView = viewMode === 'desk';
const gridIconSize = DEFAULT_GRID_ICON_SIZE;
const { openPreview } = usePreviewContext(); const { openPreview } = usePreviewContext();
@@ -472,6 +474,13 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
onEntryPointer, onEntryPointer,
}; };
const [iconSizes] = useState({
list: DEFAULT_LIST_ICON_SIZE,
grid: DEFAULT_GRID_ICON_SIZE,
desk: DEFAULT_DESKTOP_CARD_SIZE,
});
const renderBody = () => { const renderBody = () => {
const hasEntries = entries.length > 0; const hasEntries = entries.length > 0;
const isSearchEmpty = (showingSearchResults || isFilterActive) && !hasDocumentEntries && !isSearchLoading; const isSearchEmpty = (showingSearchResults || isFilterActive) && !hasDocumentEntries && !isSearchLoading;
@@ -494,12 +503,12 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
switch (viewMode) { switch (viewMode) {
case 'desk': case 'desk':
return <DesktopWorkspace {...viewProps} defaultCardSize={DEFAULT_DESKTOP_CARD_SIZE} />; return <DesktopWorkspace {...viewProps} defaultCardSize={iconSizes.desk} />;
case 'grid': case 'grid':
return <DocumentsGrid {...viewProps} iconSize={gridIconSize} />; return <DocumentsGrid {...viewProps} iconSize={iconSizes.grid} />;
case 'list': case 'list':
default: default:
return <DocumentsList {...viewProps} iconSize={DEFAULT_LIST_ICON_SIZE} />; return <DocumentsList {...viewProps} iconSize={iconSizes.list} />;
} }
}; };
@@ -519,6 +528,7 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
header={headerConfig} header={headerConfig}
onBreadcrumbClick={onBreadcrumbNavigate} onBreadcrumbClick={onBreadcrumbNavigate}
/> />
<div className="documents-panel-wrapper">
<section <section
ref={scrollRef} ref={scrollRef}
className={`documents-panel documents-panel--view-${panelVariant}`} className={`documents-panel documents-panel--view-${panelVariant}`}
@@ -526,6 +536,7 @@ const DocumentsPanelInner: React.FC<DocumentsPanelInnerProps> = ({
> >
{renderBody()} {renderBody()}
</section> </section>
</div>
</> </>
); );
}; };
@@ -806,3 +806,11 @@
text-align: center; text-align: center;
color: var(--muted); color: var(--muted);
} }
.documents-panel-wrapper {
position: relative;
display: flex;
flex-direction: column;
flex: 1 1 auto;
min-height: 0;
}