#199 - Search media files

This commit is contained in:
Elio Struyf
2021-12-27 15:56:12 +01:00
parent c5b7b7845d
commit ab3686b3b5
17 changed files with 393 additions and 263 deletions
@@ -1,28 +1,32 @@
import {CollectionIcon} from '@heroicons/react/outline';
import { CollectionIcon } from '@heroicons/react/outline';
import { basename, join } from 'path';
import * as React from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { Sorting } from '.';
import { HOME_PAGE_NAVIGATION_ID } from '../../../constants';
import { parseWinPath } from '../../../helpers/parseWinPath';
import { NavigationType } from '../../models';
import { SelectedMediaFolderAtom, SettingsAtom } from '../../state';
import { SearchAtom, SelectedMediaFolderAtom, SettingsAtom } from '../../state';
export interface IBreadcrumbProps {}
export const Breadcrumb: React.FunctionComponent<IBreadcrumbProps> = (props: React.PropsWithChildren<IBreadcrumbProps>) => {
const [ selectedFolder, setSelectedFolder ] = useRecoilState(SelectedMediaFolderAtom);
const settings = useRecoilValue(SettingsAtom);
const [ , setSearchValue ] = useRecoilState(SearchAtom);
const [ folders, setFolders ] = React.useState<string[]>([]);
const settings = useRecoilValue(SettingsAtom);
if (!settings?.wsFolder) {
return null;
const updateFolder = (folder: string) => {
setSearchValue('');
setSelectedFolder(folder);
}
React.useEffect(() => {
if (!settings) {
return;
}
const { wsFolder, staticFolder, contentFolders } = settings;
const isValid = (folderPath: string) => {
const isValid = (folderPath: string) => {
if (staticFolder) {
const staticPath = parseWinPath(join(wsFolder, staticFolder)) as string;
const relPath = folderPath.replace(staticPath, '') as string;
@@ -33,7 +37,7 @@ export const Breadcrumb: React.FunctionComponent<IBreadcrumbProps> = (props: Rea
return false;
}
}
1
for (let i = 0; i < contentFolders.length; i++) {
const folder = contentFolders[i];
const contentFolder = parseWinPath(folder.path) as string;
@@ -62,45 +66,40 @@ export const Breadcrumb: React.FunctionComponent<IBreadcrumbProps> = (props: Rea
setFolders(allFolders);
}
}, [selectedFolder]);
}, [selectedFolder, settings]);
return (
<nav className="w-full bg-gray-200 text-vulcan-300 dark:bg-vulcan-400 dark:text-whisper-600 border-b border-gray-300 dark:border-vulcan-100 flex justify-between py-2" aria-label="Breadcrumb">
<ol role="list" className="flex space-x-4 px-5">
<li className="flex">
<ol role="list" className="flex space-x-4 px-5 flex-1">
<li className="flex">
<div className="flex items-center">
<button onClick={() => setSelectedFolder(HOME_PAGE_NAVIGATION_ID)} className="text-gray-500 hover:text-gray-600 dark:text-whisper-900 dark:hover:text-whisper-500">
<CollectionIcon className="flex-shrink-0 h-5 w-5" aria-hidden="true" />
<span className="sr-only">Home</span>
</button>
</div>
</li>
{folders.map((folder) => (
<li key={folder} className="flex">
<div className="flex items-center">
<button onClick={() => setSelectedFolder(HOME_PAGE_NAVIGATION_ID)} className="text-gray-500 hover:text-gray-600 dark:text-whisper-900 dark:hover:text-whisper-500">
<CollectionIcon className="flex-shrink-0 h-5 w-5" aria-hidden="true" />
<span className="sr-only">Home</span>
<svg
className="flex-shrink-0 h-5 w-5 text-gray-300 dark:text-whisper-900"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 20 20"
aria-hidden="true"
>
<path d="M5.555 17.776l8-16 .894.448-8 16-.894-.448z" />
</svg>
<button
onClick={() => updateFolder(folder)}
className="ml-4 text-sm font-medium text-gray-500 hover:text-gray-600 dark:text-whisper-900 dark:hover:text-whisper-500"
>
{basename(folder)}
</button>
</div>
</li>
{folders.map((folder) => (
<li key={folder} className="flex">
<div className="flex items-center">
<svg
className="flex-shrink-0 h-5 w-5 text-gray-300 dark:text-whisper-900"
xmlns="http://www.w3.org/2000/svg"
fill="currentColor"
viewBox="0 0 20 20"
aria-hidden="true"
>
<path d="M5.555 17.776l8-16 .894.448-8 16-.894-.448z" />
</svg>
<button
onClick={() => setSelectedFolder(folder)}
className="ml-4 text-sm font-medium text-gray-500 hover:text-gray-600 dark:text-whisper-900 dark:hover:text-whisper-500"
>
{basename(folder)}
</button>
</div>
</li>
))}
</ol>
<div className={`flex px-5`}>
<Sorting view={NavigationType.Media} disableCustomSorting />
</div>
</nav>
))}
</ol>
);
};
@@ -15,9 +15,9 @@ import { Messenger } from '@estruyf/vscode/dist/client';
import { ClearFilters } from './ClearFilters';
import { MarkdownIcon } from '../../../panelWebView/components/Icons/MarkdownIcon';
import {PhotographIcon} from '@heroicons/react/outline';
import { Pagination } from '../Media/Pagination';
import { MediaHeaderTop } from '../Media/MediaHeaderTop';
import { ChoiceButton } from '../ChoiceButton';
import { Breadcrumb } from './Breadcrumb';
import { MediaHeaderBottom } from '../Media/MediaHeaderBottom';
export interface IHeaderProps {
settings: Settings | null;
@@ -125,8 +125,9 @@ export const Header: React.FunctionComponent<IHeaderProps> = ({totalPages, folde
{
view === NavigationType.Media && (
<>
<Pagination />
<Breadcrumb />
<MediaHeaderTop />
<MediaHeaderBottom />
</>
)
}
@@ -0,0 +1,72 @@
import * as React from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { LIMIT } from '../../hooks/useMedia';
import { MediaTotalSelector, PageAtom } from '../../state';
import { PaginationButton } from './PaginationButton';
export interface IPaginationProps {}
export const Pagination: React.FunctionComponent<IPaginationProps> = (props: React.PropsWithChildren<IPaginationProps>) => {
const [ page, setPage ] = useRecoilState(PageAtom);
const totalMedia = useRecoilValue(MediaTotalSelector);
const totalPages = Math.ceil(totalMedia / LIMIT) - 1;
const getButtons = (): number[] => {
const maxButtons = 5;
const buttons: number[] = [];
const start = page - maxButtons;
const end = page + maxButtons;
for (let i = start; i <= end; i++) {
if (i >= 0 && i <= totalPages) {
buttons.push(i);
}
}
return buttons;
};
return (
<div className="flex justify-between items-center sm:justify-end space-x-2 text-sm">
<PaginationButton
title="First"
disabled={page === 0}
onClick={() => {
if (page > 0) {
setPage(0)
}
}} />
<PaginationButton
title="Previous"
disabled={page === 0}
onClick={() => {
if (page > 0) {
setPage(page - 1)
}
}} />
{getButtons().map((button) => (
<button
key={button}
disabled={button === page}
onClick={() => {
setPage(button)
}
}
className={`${page === button ? 'bg-gray-200 px-2 text-vulcan-500' : 'text-gray-500 hover:text-gray-600 dark:text-whisper-900 dark:hover:text-whisper-500'} max-h-8`}
>{button + 1}</button>
))}
<PaginationButton
title="Next"
disabled={page >= totalPages}
onClick={() => setPage(page + 1)} />
<PaginationButton
title="Last"
disabled={page >= totalPages}
onClick={() => setPage(totalPages)} />
</div>
);
};
@@ -0,0 +1,46 @@
import * as React from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { MediaTotalSelector, PageAtom, SearchAtom, SelectedMediaFolderSelector } from '../../state';
import { Messenger } from '@estruyf/vscode/dist/client';
import { DashboardMessage } from '../../DashboardMessage';
import { RefreshIcon } from '@heroicons/react/outline';
import { LIMIT } from '../../hooks/useMedia';
export interface IPaginationStatusProps {}
export const PaginationStatus: React.FunctionComponent<IPaginationStatusProps> = (props: React.PropsWithChildren<IPaginationStatusProps>) => {
const totalMedia = useRecoilValue(MediaTotalSelector);
const selectedFolder = useRecoilValue(SelectedMediaFolderSelector);
const [ page, setPage ] = useRecoilState(PageAtom);
const [ , setSearch ] = useRecoilState(SearchAtom);
const getTotalPage = () => {
const mediaItems = ((page + 1) * LIMIT);
if (totalMedia < mediaItems) {
return totalMedia;
}
return mediaItems;
};
const refresh = () => {
setPage(0);
setSearch('');
Messenger.send(DashboardMessage.refreshMedia, { folder: selectedFolder });
}
return (
<div className="hidden sm:flex">
<button className={`mr-2 text-gray-500 hover:text-gray-600 dark:text-whisper-900 dark:hover:text-whisper-500`}
title="Refresh media"
onClick={refresh}>
<RefreshIcon className={`h-5 w-5`} />
<span className="sr-only">Refresh media</span>
</button>
<p className="text-sm text-gray-500 dark:text-whisper-900">
Showing <span className="font-medium">{(page * LIMIT) + 1}</span> to <span className="font-medium">{getTotalPage()}</span> of{' '}
<span className="font-medium">{totalMedia}</span> results
</p>
</div>
);
};
@@ -8,25 +8,32 @@ export interface ISearchboxProps {}
export const Searchbox: React.FunctionComponent<ISearchboxProps> = ({}: React.PropsWithChildren<ISearchboxProps>) => {
const [ value, setValue ] = React.useState('');
const [ , setDebounceValue ] = useRecoilState(SearchAtom);
const [ debounceSearchValue, setDebounceValue ] = useRecoilState(SearchAtom);
const debounceSearch = useDebounce<string>(value, 500);
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setValue(event.target.value);
};
React.useEffect(() => {
if (!debounceSearchValue && value) {
setValue('');
}
} , [debounceSearchValue]);
React.useEffect(() => {
setDebounceValue(debounceSearch);
}, [debounceSearch]);
return (
<div className="flex space-x-4">
<div className="flex-1 min-w-0">
<div className="flex space-x-4 flex-1">
<div className="min-w-0">
<label htmlFor="search" className="sr-only">Search</label>
<div className="relative flex justify-center">
<div className="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<SearchIcon className="h-5 w-5 text-gray-400" aria-hidden="true" />
</div>
<input
type="search"
name="search"
@@ -26,24 +26,28 @@ export const FolderCreation: React.FunctionComponent<IFolderCreationProps> = (pr
const scripts = (settings?.scripts || []).filter(script => script.type === ScriptType.MediaFolder);
if (scripts.length > 0) {
return (
<ChoiceButton
title={`Create new folder`}
choices={scripts.map(s => ({
title: s.title,
onClick: () => runCustomScript(s)
}))}
onClick={onFolderCreation}
disabled={!settings?.initialized} />
<div className="flex flex-1 justify-end">
<ChoiceButton
title={`Create new folder`}
choices={scripts.map(s => ({
title: s.title,
onClick: () => runCustomScript(s)
}))}
onClick={onFolderCreation}
disabled={!settings?.initialized} />
</div>
)
}
return (
<button
className={`inline-flex items-center px-3 py-1 border border-transparent text-xs leading-4 font-medium text-white dark:text-vulcan-500 bg-teal-600 hover:bg-teal-700 focus:outline-none disabled:bg-gray-500`}
title={`Create new folder`}
onClick={onFolderCreation}>
<FolderAddIcon className={`mr-2 h-6 w-6`} />
<span className={``}>Create new folder</span>
</button>
<div className="flex flex-1 justify-end">
<button
className={`inline-flex items-center px-3 py-1 border border-transparent text-xs leading-4 font-medium text-white dark:text-vulcan-500 bg-teal-600 hover:bg-teal-700 focus:outline-none disabled:bg-gray-500`}
title={`Create new folder`}
onClick={onFolderCreation}>
<FolderAddIcon className={`mr-2 h-6 w-6`} />
<span className={``}>Create new folder</span>
</button>
</div>
);
};
@@ -17,19 +17,17 @@ import { useCallback } from 'react';
import { DashboardMessage } from '../../DashboardMessage';
import { FrontMatterIcon } from '../../../panelWebView/components/Icons/FrontMatterIcon';
import { FolderItem } from './FolderItem';
import useMedia from '../../hooks/useMedia';
export interface IMediaProps {}
export const LIMIT = 16;
export const Media: React.FunctionComponent<IMediaProps> = (props: React.PropsWithChildren<IMediaProps>) => {
const { media } = useMedia();
const settings = useRecoilValue(SettingsSelector);
const [ selectedFolder, setSelectedFolder ] = useRecoilState(SelectedMediaFolderAtom);
const [ media, setMedia ] = React.useState<MediaInfo[]>([]);
const [ , setTotal ] = useRecoilState(MediaTotalAtom);
const [ folders, setFolders ] = useRecoilState(MediaFoldersAtom);
const [ loading, setLoading ] = useRecoilState(LoadingAtom);
const viewData = useRecoilValue(ViewDataSelector);
const selectedFolder = useRecoilValue(SelectedMediaFolderAtom);
const folders = useRecoilValue(MediaFoldersAtom);
const loading = useRecoilValue(LoadingAtom);
const onDrop = useCallback((acceptedFiles: File[]) => {
acceptedFiles.forEach((file) => {
@@ -52,25 +50,6 @@ export const Media: React.FunctionComponent<IMediaProps> = (props: React.PropsWi
onDrop,
accept: 'image/*'
});
const messageListener = (message: MessageEvent<EventData<MediaPaths | { key: string, value: any }>>) => {
if (message.data.command === DashboardCommand.media) {
const data: MediaPaths = message.data.data as MediaPaths;
setLoading(false);
setMedia(data.media);
setTotal(data.total);
setFolders(data.folders);
setSelectedFolder(data.selectedFolder);
}
};
React.useEffect(() => {
Messenger.listen<MediaPaths>(messageListener);
return () => {
Messenger.unlisten(messageListener);
}
}, ['']);
return (
<div className="flex flex-col h-full overflow-auto">
@@ -0,0 +1,30 @@
import * as React from 'react';
import { useRecoilValue } from 'recoil';
import { NavigationType } from '../../models/NavigationType';
import { SettingsAtom } from '../../state';
import { Sorting } from '../Header';
import { Breadcrumb } from '../Header/Breadcrumb';
import { Pagination } from '../Header/Pagination';
export interface IMediaHeaderBottomProps {}
export const MediaHeaderBottom: React.FunctionComponent<IMediaHeaderBottomProps> = (props: React.PropsWithChildren<IMediaHeaderBottomProps>) => {
const settings = useRecoilValue(SettingsAtom);
if (!settings?.wsFolder) {
return null;
}
return (
<nav className="w-full bg-gray-200 text-vulcan-300 dark:bg-vulcan-400 dark:text-whisper-600 border-b border-gray-300 dark:border-vulcan-100 flex justify-between py-2" aria-label="Breadcrumb">
<Breadcrumb />
<Pagination />
<div className={`flex px-5 flex-1 justify-end`}>
<Sorting view={NavigationType.Media} disableCustomSorting />
</div>
</nav>
);
};
@@ -0,0 +1,81 @@
import { EventData } from '@estruyf/vscode';
import { Messenger } from '@estruyf/vscode/dist/client';
import * as React from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { useDebounce } from '../../../hooks/useDebounce';
import { usePrevious } from '../../../panelWebView/hooks/usePrevious';
import { DashboardCommand } from '../../DashboardCommand';
import { DashboardMessage } from '../../DashboardMessage';
import { LoadingAtom, PageAtom, SelectedMediaFolderSelector, SettingsSelector, SortingSelector } from '../../state';
import { Searchbox } from '../Header';
import { PaginationStatus } from '../Header/PaginationStatus';
import { FolderCreation } from './FolderCreation';
export interface IMediaHeaderTopProps {}
export const MediaHeaderTop: React.FunctionComponent<IMediaHeaderTopProps> = ({}: React.PropsWithChildren<IMediaHeaderTopProps>) => {
const [ lastUpdated, setLastUpdated ] = React.useState<string | null>(null);
const selectedFolder = useRecoilValue(SelectedMediaFolderSelector);
const crntSorting = useRecoilValue(SortingSelector);
const [ , setLoading ] = useRecoilState(LoadingAtom);
const [ page, setPage ] = useRecoilState(PageAtom);
const settings = useRecoilValue(SettingsSelector);
const debounceGetMedia = useDebounce<string | null>(lastUpdated, 200);
const prevSelectedFolder = usePrevious<string | null>(selectedFolder);
const mediaUpdate = (message: MessageEvent<EventData<{ key: string, value: any }>>) => {
if (message.data.command === DashboardCommand.mediaUpdate) {
setLoading(true);
Messenger.send(DashboardMessage.getMedia, {
page,
folder: selectedFolder || '',
sorting: crntSorting
});
}
}
React.useEffect(() => {
if (prevSelectedFolder !== null || settings?.dashboardState?.media.selectedFolder !== selectedFolder) {
setLoading(true);
setPage(0);
setLastUpdated(new Date().getTime().toString());
}
}, [selectedFolder]);
React.useEffect(() => {
setLastUpdated(new Date().getTime().toString());
}, [crntSorting]);
React.useEffect(() => {
if (debounceGetMedia) {
setLoading(true);
Messenger.send(DashboardMessage.getMedia, {
page,
folder: selectedFolder || '',
sorting: crntSorting
});
}
}, [debounceGetMedia]);
React.useEffect(() => {
Messenger.listen(mediaUpdate);
return () => {
Messenger.unlisten(mediaUpdate);
}
}, []);
return (
<nav
className="py-4 px-5 flex items-center justify-between border-b border-gray-300 dark:border-vulcan-100"
aria-label="Pagination"
>
<Searchbox />
<PaginationStatus />
<FolderCreation />
</nav>
);
};
@@ -1,169 +0,0 @@
import { EventData } from '@estruyf/vscode';
import { Messenger } from '@estruyf/vscode/dist/client';
import {RefreshIcon} from '@heroicons/react/outline';
import * as React from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { useDebounce } from '../../../hooks/useDebounce';
import { usePrevious } from '../../../panelWebView/hooks/usePrevious';
import { DashboardCommand } from '../../DashboardCommand';
import { DashboardMessage } from '../../DashboardMessage';
import { LoadingAtom, MediaTotalSelector, PageAtom, SelectedMediaFolderSelector, SettingsSelector, SortingSelector } from '../../state';
import { FolderCreation } from './FolderCreation';
import { LIMIT } from './Media';
import { PaginationButton } from './PaginationButton';
export interface IPaginationProps {}
export const Pagination: React.FunctionComponent<IPaginationProps> = ({}: React.PropsWithChildren<IPaginationProps>) => {
const [ lastUpdated, setLastUpdated ] = React.useState<string | null>(null);
const selectedFolder = useRecoilValue(SelectedMediaFolderSelector);
const crntSorting = useRecoilValue(SortingSelector);
const totalMedia = useRecoilValue(MediaTotalSelector);
const [ , setLoading ] = useRecoilState(LoadingAtom);
const [ page, setPage ] = useRecoilState(PageAtom);
const settings = useRecoilValue(SettingsSelector);
const debounceGetMedia = useDebounce<string | null>(lastUpdated, 200);
const prevSelectedFolder = usePrevious<string | null>(selectedFolder);
const totalPages = Math.ceil(totalMedia / LIMIT) - 1;
const getTotalPage = () => {
const mediaItems = ((page + 1) * LIMIT);
if (totalMedia < mediaItems) {
return totalMedia;
}
return mediaItems;
};
// Write me function to retrieve buttons before and after current page
const getButtons = (): number[] => {
const maxButtons = 5;
const buttons: number[] = [];
const start = page - maxButtons;
const end = page + maxButtons;
for (let i = start; i <= end; i++) {
if (i >= 0 && i <= totalPages) {
buttons.push(i);
}
}
return buttons;
};
const refresh = () => {
setPage(0);
Messenger.send(DashboardMessage.refreshMedia, { folder: selectedFolder });
}
const mediaUpdate = (message: MessageEvent<EventData<{ key: string, value: any }>>) => {
if (message.data.command === DashboardCommand.mediaUpdate) {
setLoading(true);
Messenger.send(DashboardMessage.getMedia, {
page,
folder: selectedFolder || '',
sorting: crntSorting
});
}
}
React.useEffect(() => {
setLastUpdated(new Date().getTime().toString());
}, [page]);
React.useEffect(() => {
if (prevSelectedFolder !== null || settings?.dashboardState?.media.selectedFolder !== selectedFolder) {
setLoading(true);
setPage(0);
setLastUpdated(new Date().getTime().toString());
}
}, [selectedFolder]);
React.useEffect(() => {
setLastUpdated(new Date().getTime().toString());
}, [crntSorting]);
React.useEffect(() => {
if (debounceGetMedia) {
setLoading(true);
Messenger.send(DashboardMessage.getMedia, {
page,
folder: selectedFolder || '',
sorting: crntSorting
});
}
}, [debounceGetMedia]);
React.useEffect(() => {
Messenger.listen(mediaUpdate);
return () => {
Messenger.unlisten(mediaUpdate);
}
}, []);
return (
<nav
className="py-4 px-5 flex items-center justify-between bg-gray-200 border-b border-gray-300 dark:bg-vulcan-400 dark:border-vulcan-100"
aria-label="Pagination"
>
<div className="hidden sm:flex">
<button className={`mr-2 text-gray-500 hover:text-gray-600 dark:text-whisper-900 dark:hover:text-whisper-500`}
title="Refresh media"
onClick={refresh}>
<RefreshIcon className={`h-5 w-5`} />
<span className="sr-only">Refresh media</span>
</button>
<p className="text-sm text-gray-500 dark:text-whisper-900">
Showing <span className="font-medium">{(page * LIMIT) + 1}</span> to <span className="font-medium">{getTotalPage()}</span> of{' '}
<span className="font-medium">{totalMedia}</span> results
</p>
</div>
<FolderCreation />
<div className="flex justify-between sm:justify-end space-x-2 text-sm">
<PaginationButton
title="First"
disabled={page === 0}
onClick={() => {
if (page > 0) {
setPage(0)
}
}} />
<PaginationButton
title="Previous"
disabled={page === 0}
onClick={() => {
if (page > 0) {
setPage(page - 1)
}
}} />
{getButtons().map((button) => (
<button
key={button}
disabled={button === page}
onClick={() => {
setPage(button)
}
}
className={`${page === button ? 'bg-gray-200 px-2 text-vulcan-500' : 'text-gray-500 hover:text-gray-600 dark:text-whisper-900 dark:hover:text-whisper-500'}`}
>{button + 1}</button>
))}
<PaginationButton
title="Next"
disabled={page >= totalPages}
onClick={() => setPage(page + 1)} />
<PaginationButton
title="Last"
disabled={page >= totalPages}
onClick={() => setPage(totalPages)} />
</div>
</nav>
);
};
+1 -1
View File
@@ -21,7 +21,7 @@ export const Startup: React.FunctionComponent<IStartupProps> = ({settings}: Reac
}, [settings?.openOnStart]);
return (
<div className={`relative flex items-start`}>
<div className={`relative flex items-start ml-4`}>
<div className="flex items-center h-5">
<input
id="startup"
+75
View File
@@ -0,0 +1,75 @@
import { Messenger } from '@estruyf/vscode/dist/client';
import { EventData } from '@estruyf/vscode/dist/models';
import { useState, useEffect, useCallback } from 'react';
import { useRecoilState, useRecoilValue } from 'recoil';
import { MediaInfo, MediaPaths } from '../../models';
import { DashboardCommand } from '../DashboardCommand';
import { LoadingAtom, MediaFoldersAtom, MediaTotalAtom, PageAtom, SearchAtom, SearchSelector, SelectedMediaFolderAtom } from '../state';
import Fuse from 'fuse.js';
const fuseOptions: Fuse.IFuseOptions<MediaInfo> = {
keys: [
{ name: 'filename', weight: 0.8 },
{ name: 'fsPath', weight: 0.5 },
{ name: 'caption', weight: 0.5 },
{ name: 'alt', weight: 0.5 }
],
threshold: 0.2,
includeScore: true
};
export const LIMIT = 16;
export default function useMedia() {
const [ media, setMedia ] = useState<MediaInfo[]>([]);
const [ page, setPage ] = useRecoilState(PageAtom);
const [ searchedMedia, setSearchedMedia ] = useState<MediaInfo[]>([]);
const [ , setSelectedFolder ] = useRecoilState(SelectedMediaFolderAtom);
const [ , setTotal ] = useRecoilState(MediaTotalAtom);
const [ , setFolders ] = useRecoilState(MediaFoldersAtom);
const [ , setLoading ] = useRecoilState(LoadingAtom);
const search = useRecoilValue(SearchAtom);
const getMedia = useCallback(() => {
return searchedMedia.slice(page * LIMIT, ((page + 1) * LIMIT));
}, [searchedMedia, page]);
const messageListener = (message: MessageEvent<EventData<MediaPaths | { key: string, value: any }>>) => {
if (message.data.command === DashboardCommand.media) {
const data: MediaPaths = message.data.data as MediaPaths;
setLoading(false);
setMedia(data.media);
setTotal(data.total);
setFolders(data.folders);
setSelectedFolder(data.selectedFolder);
setSearchedMedia(data.media);
}
};
useEffect(() => {
if (search) {
const fuse = new Fuse(media, fuseOptions);
const results = fuse.search(search);
const newSearchedMedia = results.map(page => page.item);
setSearchedMedia(newSearchedMedia);
setTotal(results.length);
return;
}
setSearchedMedia(media);
}, [search]);
useEffect(() => {
Messenger.listen<MediaPaths>(messageListener);
return () => {
Messenger.unlisten(messageListener);
}
}, []);
return {
media: getMedia()
};
}
+1 -1
View File
@@ -111,7 +111,6 @@ export class MediaHelpers {
const total = files.length;
// Get media set
files = files.slice(page * 16, ((page + 1) * 16));
files = files.map((file) => {
try {
const metadata = MediaLibrary.getInstance().get(file.fsPath);
@@ -323,6 +322,7 @@ export class MediaHelpers {
const ext = extname(file.fsPath);
return ['.jpg', '.jpeg', '.png', '.gif', '.svg'].includes(ext.toLowerCase());
}).map((file) => ({
filename: basename(file.fsPath),
fsPath: file.fsPath,
vsPath: Dashboard.getWebview()?.asWebviewUri(file).toString(),
stats: undefined
+1
View File
@@ -8,6 +8,7 @@ export interface MediaPaths {
}
export interface MediaInfo {
filename: string;
fsPath: string;
vsPath: string | undefined;
dimensions?: ISizeCalculationResult | undefined;