mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-02 10:03:28 +00:00
[MOB-97] Fade select tags and empty location state (#2496)
* fade select tags and empty location state * smaller tags * smaller tags in filters and add tags modal
This commit is contained in:
parent
ce3d4ff7a6
commit
96a45ee76c
|
@ -1,11 +1,12 @@
|
||||||
import { Tag, getItemObject, useLibraryMutation, useLibraryQuery, useRspcContext } from "@sd/client";
|
import { Tag, getItemObject, useLibraryMutation, useLibraryQuery, useRspcContext } from "@sd/client";
|
||||||
import { CaretLeft, Plus } from "phosphor-react-native";
|
import { CaretLeft, Plus } from "phosphor-react-native";
|
||||||
import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
||||||
import { FlatList, Pressable, Text, View } from "react-native";
|
import { FlatList, NativeScrollEvent, Pressable, Text, View } from "react-native";
|
||||||
import useForwardedRef from "~/hooks/useForwardedRef";
|
import useForwardedRef from "~/hooks/useForwardedRef";
|
||||||
import { tw, twStyle } from "~/lib/tailwind";
|
import { tw, twStyle } from "~/lib/tailwind";
|
||||||
import { useActionsModalStore } from "~/stores/modalStore";
|
import { useActionsModalStore } from "~/stores/modalStore";
|
||||||
import Card from "../layout/Card";
|
import Card from "../layout/Card";
|
||||||
|
import Fade from "../layout/Fade";
|
||||||
import { Modal, ModalRef } from "../layout/Modal";
|
import { Modal, ModalRef } from "../layout/Modal";
|
||||||
import { Button } from "../primitive/Button";
|
import { Button } from "../primitive/Button";
|
||||||
import CreateTagModal from "./tag/CreateTagModal";
|
import CreateTagModal from "./tag/CreateTagModal";
|
||||||
|
@ -20,6 +21,8 @@ const AddTagModal = forwardRef<ModalRef, unknown>((_, ref) => {
|
||||||
|
|
||||||
const modalRef = useForwardedRef(ref);
|
const modalRef = useForwardedRef(ref);
|
||||||
const newTagRef = useRef<ModalRef>(null);
|
const newTagRef = useRef<ModalRef>(null);
|
||||||
|
const [startedScrolling, setStartedScrolling] = useState(false);
|
||||||
|
const [reachedBottom, setReachedBottom] = useState(true); // needs to be set to true for initial rendering fade to be correct
|
||||||
|
|
||||||
const rspc = useRspcContext();
|
const rspc = useRspcContext();
|
||||||
const tagsQuery = useLibraryQuery(['tags.list']);
|
const tagsQuery = useLibraryQuery(['tags.list']);
|
||||||
|
@ -98,6 +101,15 @@ const AddTagModal = forwardRef<ModalRef, unknown>((_, ref) => {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fade the tags when scrolling
|
||||||
|
const fadeScroll = ({ layoutMeasurement, contentOffset, contentSize }: NativeScrollEvent) => {
|
||||||
|
const isScrolling = contentOffset.y > 0;
|
||||||
|
setStartedScrolling(isScrolling);
|
||||||
|
|
||||||
|
const hasReachedBottom = layoutMeasurement.height + contentOffset.y >= contentSize.height;
|
||||||
|
setReachedBottom(hasReachedBottom);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Modal
|
<Modal
|
||||||
|
@ -115,18 +127,37 @@ const AddTagModal = forwardRef<ModalRef, unknown>((_, ref) => {
|
||||||
>
|
>
|
||||||
<CaretLeft color={tw.color('ink')} size={16} weight="bold" />
|
<CaretLeft color={tw.color('ink')} size={16} weight="bold" />
|
||||||
</Pressable>
|
</Pressable>
|
||||||
|
<View onLayout={(e) => {
|
||||||
|
if (e.nativeEvent.layout.height >= 80) {
|
||||||
|
setReachedBottom(false);
|
||||||
|
} else {
|
||||||
|
setReachedBottom(true);
|
||||||
|
}
|
||||||
|
}} style={twStyle(`relative mt-4 h-[70%]`)}>
|
||||||
|
<Fade
|
||||||
|
fadeSides="top-bottom"
|
||||||
|
orientation="vertical"
|
||||||
|
color="bg-app-modal"
|
||||||
|
width={20}
|
||||||
|
topFadeStyle={twStyle(startedScrolling ? 'mt-0 h-6' : 'h-0')}
|
||||||
|
bottomFadeStyle={twStyle(reachedBottom ? 'h-0' : 'h-6')}
|
||||||
|
height="100%"
|
||||||
|
>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={tagsData}
|
data={tagsData}
|
||||||
numColumns={3}
|
numColumns={3}
|
||||||
|
onScroll={(e) => fadeScroll(e.nativeEvent)}
|
||||||
extraData={selectedTags}
|
extraData={selectedTags}
|
||||||
key={tagsData ? 'tags' : '_'}
|
key={tagsData ? 'tags' : '_'}
|
||||||
keyExtractor={(item) => item.id.toString()}
|
keyExtractor={(item) => item.id.toString()}
|
||||||
contentContainerStyle={tw`mx-auto mt-4 p-4 pb-10`}
|
contentContainerStyle={tw`mx-auto p-4 pb-6`}
|
||||||
ItemSeparatorComponent={() => <View style={tw`h-2`} />}
|
ItemSeparatorComponent={() => <View style={tw`h-2`} />}
|
||||||
renderItem={({ item }) => (
|
renderItem={({ item }) => (
|
||||||
<TagItem isSelected={() => isSelected(item.id)} select={() => selectTag(item.id)} tag={item} />
|
<TagItem isSelected={() => isSelected(item.id)} select={() => selectTag(item.id)} tag={item} />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
</Fade>
|
||||||
|
</View>
|
||||||
<View style={tw`flex-row gap-2 px-5`}>
|
<View style={tw`flex-row gap-2 px-5`}>
|
||||||
<Button
|
<Button
|
||||||
onPress={() => newTagRef.current?.present()}
|
onPress={() => newTagRef.current?.present()}
|
||||||
|
@ -164,7 +195,7 @@ const TagItem = ({tag, select, isSelected}: Props) => {
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={twStyle(`h-4 w-4 rounded-full`, {
|
style={twStyle(`h-3.5 w-3.5 rounded-full`, {
|
||||||
backgroundColor: tag.color!
|
backgroundColor: tag.color!
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -179,16 +179,16 @@ const ExtensionView = ({ extensions }: { extensions: string[] }) => (
|
||||||
);
|
);
|
||||||
|
|
||||||
const TagView = ({ tags }: { tags: TagItem[] }) => (
|
const TagView = ({ tags }: { tags: TagItem[] }) => (
|
||||||
<>
|
<View style={tw`mx-auto flex-row items-center justify-center`}>
|
||||||
{tags.map((tag) => (
|
{tags.map((tag) => (
|
||||||
<View
|
<View
|
||||||
key={tag.id}
|
key={tag.id}
|
||||||
style={twStyle(`h-5 w-5 rounded-full`, {
|
style={twStyle(`h-4.5 w-4.5 relative rounded-full border-2 border-app-card`, {
|
||||||
backgroundColor: tag.color
|
backgroundColor: tag.color,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
</>
|
</View>
|
||||||
);
|
);
|
||||||
|
|
||||||
const LocationView = ({ locations }: { locations: FilterItemType[] }) => (
|
const LocationView = ({ locations }: { locations: FilterItemType[] }) => (
|
||||||
|
|
|
@ -76,7 +76,7 @@ const TagFilter = memo(({ tag }: Props) => {
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<View
|
<View
|
||||||
style={twStyle(`h-5 w-5 rounded-full`, {
|
style={twStyle(`h-3.5 w-3.5 rounded-full`, {
|
||||||
backgroundColor: tag.color!
|
backgroundColor: tag.color!
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
import { useLibraryQuery, usePathsExplorerQuery } from '@sd/client';
|
import { useLibraryQuery, usePathsExplorerQuery } from '@sd/client';
|
||||||
import { useEffect, useMemo } from 'react';
|
import { useEffect, useMemo } from 'react';
|
||||||
import Explorer from '~/components/explorer/Explorer';
|
import Explorer from '~/components/explorer/Explorer';
|
||||||
|
import Empty from '~/components/layout/Empty';
|
||||||
import { useSortBy } from '~/hooks/useSortBy';
|
import { useSortBy } from '~/hooks/useSortBy';
|
||||||
|
import { tw } from '~/lib/tailwind';
|
||||||
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
||||||
import { getExplorerStore } from '~/stores/explorerStore';
|
import { getExplorerStore } from '~/stores/explorerStore';
|
||||||
|
|
||||||
|
@ -62,5 +64,15 @@ export default function LocationScreen({ navigation, route }: BrowseStackScreenP
|
||||||
getExplorerStore().path = path ?? '';
|
getExplorerStore().path = path ?? '';
|
||||||
}, [id, path]);
|
}, [id, path]);
|
||||||
|
|
||||||
return <Explorer {...paths} />;
|
return <Explorer
|
||||||
|
isEmpty={paths.count === 0}
|
||||||
|
emptyComponent={<Empty
|
||||||
|
includeHeaderHeight
|
||||||
|
icon={'FolderNoSpace'}
|
||||||
|
style={tw`flex-1 items-center justify-center border-0`}
|
||||||
|
textSize="text-md"
|
||||||
|
iconSize={100}
|
||||||
|
description={'No files found'}
|
||||||
|
/>}
|
||||||
|
{...paths} />
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue