1
0
mirror of https://github.com/XFox111/TabsAsideExtension.git synced 2026-04-22 07:58:01 +03:00
Files
TabsAsideExtension/entrypoints/sidepanel/layouts/collections/CollectionListView.tsx
T

151 lines
5.4 KiB
TypeScript

import CollectionView from "@/entrypoints/sidepanel/components/CollectionView";
import GroupView from "@/entrypoints/sidepanel/components/GroupView";
import { DndItem } from "@/entrypoints/sidepanel/hooks/useDndItem";
import CloudIssueMessages from "@/entrypoints/sidepanel/layouts/collections/messages/CloudIssueMessages";
import CtaMessage from "@/entrypoints/sidepanel/layouts/collections/messages/CtaMessage";
import filterCollections, { CollectionFilterType } from "@/entrypoints/sidepanel/utils/filterCollections";
import sortCollections from "@/entrypoints/sidepanel/utils/sortCollections";
import { track } from "@/features/analytics";
import useSettings from "@/hooks/useSettings";
import { CollectionItem } from "@/models/CollectionModels";
import { DndContext, DragEndEvent, DragOverlay, DragStartEvent, MouseSensor, TouchSensor, useSensor, useSensors } from "@dnd-kit/core";
import { rectSortingStrategy, SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable";
import { Body1, Button, Caption1, mergeClasses, Subtitle2 } from "@fluentui/react-components";
import { ArrowUndo20Regular, SearchInfo24Regular, Sparkle48Regular } from "@fluentui/react-icons";
import { ReactElement } from "react";
import TabView from "../../components/TabView";
import CollectionContext from "../../contexts/CollectionContext";
import { useCollections } from "../../contexts/CollectionsProvider";
import applyReorder from "../../utils/dnd/applyReorder";
import { collisionDetector } from "../../utils/dnd/collisionDetector";
import { useStyles_CollectionListView } from "./CollectionListView.styles";
import SearchBar from "./SearchBar";
import StorageCapacityIssueMessage from "./messages/StorageCapacityIssueMessage";
export default function CollectionListView(): ReactElement
{
const { tilesView, updateCollections, collections } = useCollections();
const [sortMode, setSortMode] = useSettings("sortMode");
const [query, setQuery] = useState<string>("");
const [colors, setColors] = useState<CollectionFilterType["colors"]>([]);
const [active, setActive] = useState<DndItem | null>(null);
const sensors = useSensors(
useSensor(MouseSensor, { activationConstraint: { delay: 100, tolerance: 0 } }),
useSensor(TouchSensor, { activationConstraint: { delay: 300, tolerance: 20 } })
);
const resultList = useMemo(
() => sortCollections(filterCollections(collections, { query, colors }), sortMode),
[query, colors, sortMode, collections]
);
const cls = useStyles_CollectionListView();
const resetFilter = useCallback(() =>
{
setQuery("");
setColors([]);
}, []);
const handleDragStart = (event: DragStartEvent): void =>
{
setActive(event.active.data.current as DndItem);
};
const handleDragEnd = (args: DragEndEvent): void =>
{
setActive(null);
const result: CollectionItem[] | null = applyReorder(resultList, args);
if (result !== null)
{
updateCollections(result);
if (sortMode !== "custom")
setSortMode("custom");
track("used_drag_and_drop");
}
};
if (sortMode === null || collections === null)
return <></>;
if (collections.length < 1)
return (
<article className={ cls.empty }>
<Sparkle48Regular />
<Subtitle2 align="center">{ i18n.t("main.list.empty.title") }</Subtitle2>
<Caption1 align="center">{ i18n.t("main.list.empty.message") }</Caption1>
</article>
);
return (
<article className={ cls.root }>
<SearchBar
query={ query } onQueryChange={ setQuery }
filter={ colors } onFilterChange={ setColors }
sort={ sortMode } onSortChange={ setSortMode }
onReset={ resetFilter } />
<CtaMessage className={ cls.msgBar } />
<StorageCapacityIssueMessage className={ cls.msgBar } />
<CloudIssueMessages className={ cls.msgBar } />
{ resultList.length < 1 ?
<div className={ cls.emptySearch }>
<SearchInfo24Regular />
<Subtitle2>{ i18n.t("main.list.empty_search.title") }</Subtitle2>
<Body1>{ i18n.t("main.list.empty_search.message") }</Body1>
<Button appearance="subtle" icon={ <ArrowUndo20Regular /> } onClick={ resetFilter }>
{ i18n.t("common.actions.reset_filters") }
</Button>
</div>
:
<section className={ mergeClasses(cls.collectionList, !tilesView && cls.listView) }>
<DndContext
sensors={ sensors }
collisionDetection={ collisionDetector(!tilesView) }
onDragStart={ handleDragStart }
onDragEnd={ handleDragEnd }
>
<SortableContext
items={ resultList.map((_, index) => index.toString()) }
strategy={ tilesView ? verticalListSortingStrategy : rectSortingStrategy }
>
{ resultList.map((collection, index) =>
<CollectionView key={ index } collection={ collection } index={ index } />
) }
</SortableContext>
<DragOverlay dropAnimation={ null }>
{ active !== null ?
active.item.type === "collection" ?
<CollectionView collection={ active.item } index={ -1 } dragOverlay />
:
<CollectionContext.Provider
value={ {
tabCount: 0,
collection: resultList[active.indices[0]],
hasPinnedGroup: true
} }
>
{ active.item.type === "group" ?
<GroupView group={ active.item } indices={ [-1] } dragOverlay />
:
<TabView tab={ active.item } indices={ [-1] } dragOverlay />
}
</CollectionContext.Provider>
:
<></>
}
</DragOverlay>
</DndContext>
</section>
}
</article>
);
}