mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-02 11:13:29 +00:00
parent
1a438c630e
commit
5624054f1e
|
@ -18,7 +18,7 @@ import { Button } from '../primitive/Button';
|
|||
import LibraryItem from './LibraryItem';
|
||||
|
||||
const iconStyle = tw`text-ink-faint`;
|
||||
const iconSize = 28;
|
||||
const iconSize = 24;
|
||||
export const CATEGORIES_LIST = [
|
||||
{ name: 'Albums', icon: <Images size={iconSize} style={iconStyle} /> },
|
||||
{ name: 'Places', icon: <MapPin size={iconSize} style={iconStyle} /> },
|
||||
|
|
|
@ -12,7 +12,7 @@ const Jobs = () => {
|
|||
return (
|
||||
<View style={tw`gap-3`}>
|
||||
<View style={tw`w-full flex-row items-center justify-between px-5`}>
|
||||
<Text style={tw`text-lg font-bold text-white`}>Jobs</Text>
|
||||
<Text style={tw`text-lg font-bold text-white`}>Active Jobs</Text>
|
||||
</View>
|
||||
<Fade color="black" height="100%" width={30}>
|
||||
<ScrollView horizontal showsHorizontalScrollIndicator={false}>
|
||||
|
|
|
@ -12,9 +12,9 @@ interface CategoryProps {
|
|||
const ListLibraryItem = ({ name, icon }: CategoryProps) => {
|
||||
return (
|
||||
<Card style={tw`flex-row items-center justify-between gap-2 py-3`}>
|
||||
<View style={tw`flex-row items-center gap-2`}>
|
||||
<View style={tw`flex-row items-center gap-2 px-2`}>
|
||||
{icon}
|
||||
<Text style={twStyle(`mt-0 text-sm text-white`)}>{name}</Text>
|
||||
<Text style={twStyle(`text-sm text-white`)}>{name}</Text>
|
||||
</View>
|
||||
<View
|
||||
style={tw`h-10 w-10 flex-row items-center justify-center rounded-full border border-app-lightborder/70 px-2`}
|
||||
|
|
|
@ -109,7 +109,7 @@ const useFormState = () => {
|
|||
// Switch to the new library
|
||||
currentLibraryStore.id = library.uuid;
|
||||
} catch (e) {
|
||||
toast({ type: 'error', text: 'Failed to create library' });
|
||||
toast.error('Failed to create library');
|
||||
resetOnboardingStore();
|
||||
navigation.navigate('GetStarted');
|
||||
}
|
||||
|
|
|
@ -1,20 +1,18 @@
|
|||
import { useNavigation } from '@react-navigation/native';
|
||||
import { FlashList } from '@shopify/flash-list';
|
||||
import { UseInfiniteQueryResult } from '@tanstack/react-query';
|
||||
import { AnimatePresence, MotiView } from 'moti';
|
||||
import { useState } from 'react';
|
||||
import { ActivityIndicator, Pressable } from 'react-native';
|
||||
import { isPath, SearchData, type ExplorerItem } from '@sd/client';
|
||||
import Layout from '~/constants/Layout';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { BrowseStackScreenProps } from '~/navigation/tabs/BrowseStack';
|
||||
import { ExplorerLayoutMode, getExplorerStore, useExplorerStore } from '~/stores/explorerStore';
|
||||
import { useExplorerStore } from '~/stores/explorerStore';
|
||||
import { useActionsModalStore } from '~/stores/modalStore';
|
||||
|
||||
import ScreenContainer from '../layout/ScreenContainer';
|
||||
import FileItem from './FileItem';
|
||||
import FileRow from './FileRow';
|
||||
import Menu from './Menu';
|
||||
import Menu from './menu/Menu';
|
||||
|
||||
type ExplorerProps = {
|
||||
tabHeight?: boolean;
|
||||
|
@ -27,14 +25,8 @@ type ExplorerProps = {
|
|||
|
||||
const Explorer = (props: ExplorerProps) => {
|
||||
const navigation = useNavigation<BrowseStackScreenProps<'Location'>['navigation']>();
|
||||
const explorerStore = useExplorerStore();
|
||||
const [layoutMode, setLayoutMode] = useState<ExplorerLayoutMode>(getExplorerStore().layoutMode);
|
||||
|
||||
function changeLayoutMode(kind: ExplorerLayoutMode) {
|
||||
// We need to keep layoutMode as a state to make sure flash-list re-renders.
|
||||
setLayoutMode(kind);
|
||||
getExplorerStore().layoutMode = kind;
|
||||
}
|
||||
const store = useExplorerStore();
|
||||
|
||||
const { modalRef, setData } = useActionsModalStore();
|
||||
|
||||
|
@ -52,45 +44,11 @@ const Explorer = (props: ExplorerProps) => {
|
|||
|
||||
return (
|
||||
<ScreenContainer tabHeight={props.tabHeight} scrollview={false} style={'gap-0 py-0'}>
|
||||
{/* Header */}
|
||||
{/* Sort By */}
|
||||
{/* <SortByMenu /> */}
|
||||
<AnimatePresence>
|
||||
{explorerStore.toggleMenu && (
|
||||
<MotiView
|
||||
from={{ translateY: -70 }}
|
||||
animate={{ translateY: 0 }}
|
||||
transition={{
|
||||
type: 'timing',
|
||||
duration: 300,
|
||||
repeat: 0,
|
||||
repeatReverse: false
|
||||
}}
|
||||
exit={{ translateY: -70 }}
|
||||
>
|
||||
<Menu
|
||||
changeLayoutMode={(kind: ExplorerLayoutMode) => {
|
||||
changeLayoutMode(kind);
|
||||
}}
|
||||
layoutMode={layoutMode}
|
||||
/>
|
||||
</MotiView>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
{/* Layout (Grid/List) */}
|
||||
{/* {layoutMode === 'grid' ? (
|
||||
<Pressable onPress={() => changeLayoutMode('list')}>
|
||||
<SquaresFour color={tw.color('ink')} size={23} />
|
||||
</Pressable>
|
||||
) : (
|
||||
<Pressable onPress={() => changeLayoutMode('grid')}>
|
||||
<Rows color={tw.color('ink')} size={23} />
|
||||
</Pressable>
|
||||
)} */}
|
||||
<Menu />
|
||||
{/* Items */}
|
||||
<FlashList
|
||||
key={layoutMode}
|
||||
numColumns={layoutMode === 'grid' ? getExplorerStore().gridNumColumns : 1}
|
||||
key={store.layoutMode}
|
||||
numColumns={store.layoutMode === 'grid' ? store.gridNumColumns : 1}
|
||||
data={props.items ?? []}
|
||||
keyExtractor={(item) =>
|
||||
item.type === 'NonIndexedPath'
|
||||
|
@ -101,15 +59,19 @@ const Explorer = (props: ExplorerProps) => {
|
|||
}
|
||||
renderItem={({ item }) => (
|
||||
<Pressable onPress={() => handlePress(item)}>
|
||||
{layoutMode === 'grid' ? <FileItem data={item} /> : <FileRow data={item} />}
|
||||
{store.layoutMode === 'grid' ? (
|
||||
<FileItem data={item} />
|
||||
) : (
|
||||
<FileRow data={item} />
|
||||
)}
|
||||
</Pressable>
|
||||
)}
|
||||
contentContainerStyle={tw`px-2 py-5`}
|
||||
extraData={layoutMode}
|
||||
extraData={store.layoutMode}
|
||||
estimatedItemSize={
|
||||
layoutMode === 'grid'
|
||||
? Layout.window.width / getExplorerStore().gridNumColumns
|
||||
: getExplorerStore().listItemSize
|
||||
store.layoutMode === 'grid'
|
||||
? Layout.window.width / store.gridNumColumns
|
||||
: store.listItemSize
|
||||
}
|
||||
onEndReached={() => props.loadMore?.()}
|
||||
onEndReachedThreshold={0.6}
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
import { MonitorPlay, Rows, SlidersHorizontal, SquaresFour } from 'phosphor-react-native';
|
||||
import { Pressable, View } from 'react-native';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { ExplorerLayoutMode } from '~/stores/explorerStore';
|
||||
|
||||
interface MenuProps {
|
||||
layoutMode: ExplorerLayoutMode;
|
||||
changeLayoutMode: (kind: ExplorerLayoutMode) => void;
|
||||
}
|
||||
|
||||
const Menu = ({ layoutMode, changeLayoutMode }: MenuProps) => {
|
||||
return (
|
||||
<View
|
||||
style={tw`w-screen flex-row justify-between border-b border-app-cardborder bg-app-header px-7 py-4`}
|
||||
>
|
||||
<View style={tw`flex-row gap-3`}>
|
||||
<Pressable hitSlop={24} onPress={() => changeLayoutMode('grid')}>
|
||||
<SquaresFour
|
||||
color={tw.color(layoutMode === 'grid' ? 'text-accent' : 'text-ink-dull')}
|
||||
size={23}
|
||||
/>
|
||||
</Pressable>
|
||||
<Pressable hitSlop={24} onPress={() => changeLayoutMode('list')}>
|
||||
<Rows
|
||||
color={tw.color(layoutMode === 'list' ? 'text-accent' : 'text-ink-dull')}
|
||||
size={23}
|
||||
/>
|
||||
</Pressable>
|
||||
<Pressable hitSlop={24} onPress={() => changeLayoutMode('media')}>
|
||||
<MonitorPlay
|
||||
color={tw.color(layoutMode === 'media' ? 'text-accent' : 'text-ink-dull')}
|
||||
size={23}
|
||||
/>
|
||||
</Pressable>
|
||||
</View>
|
||||
<SlidersHorizontal style={tw`text-ink-dull`} />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
export default Menu;
|
72
apps/mobile/src/components/explorer/menu/Menu.tsx
Normal file
72
apps/mobile/src/components/explorer/menu/Menu.tsx
Normal file
|
@ -0,0 +1,72 @@
|
|||
import { AnimatePresence, MotiView } from 'moti';
|
||||
import { MonitorPlay, Rows, SlidersHorizontal, SquaresFour } from 'phosphor-react-native';
|
||||
import { Pressable, View } from 'react-native';
|
||||
import { toast } from '~/components/primitive/Toast';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
import { getExplorerStore, useExplorerStore } from '~/stores/explorerStore';
|
||||
|
||||
import SortByMenu from './SortByMenu';
|
||||
|
||||
const Menu = () => {
|
||||
const store = useExplorerStore();
|
||||
|
||||
return (
|
||||
<AnimatePresence>
|
||||
{store.toggleMenu && (
|
||||
<MotiView
|
||||
from={{ translateY: -70 }}
|
||||
animate={{ translateY: 0 }}
|
||||
transition={{
|
||||
type: 'timing',
|
||||
duration: 300,
|
||||
repeat: 0,
|
||||
repeatReverse: false
|
||||
}}
|
||||
exit={{ translateY: -70 }}
|
||||
>
|
||||
<View
|
||||
style={tw`w-screen flex-row items-center justify-between border-b border-app-cardborder bg-app-header px-7 py-4`}
|
||||
>
|
||||
<View style={tw`flex-row gap-3`}>
|
||||
<Pressable onPress={() => (getExplorerStore().layoutMode = 'grid')}>
|
||||
<SquaresFour
|
||||
color={tw.color(
|
||||
store.layoutMode === 'grid'
|
||||
? 'text-accent'
|
||||
: 'text-ink-dull'
|
||||
)}
|
||||
size={23}
|
||||
/>
|
||||
</Pressable>
|
||||
<Pressable onPress={() => (getExplorerStore().layoutMode = 'list')}>
|
||||
<Rows
|
||||
color={tw.color(
|
||||
store.layoutMode === 'list'
|
||||
? 'text-accent'
|
||||
: 'text-ink-dull'
|
||||
)}
|
||||
size={23}
|
||||
/>
|
||||
</Pressable>
|
||||
<Pressable
|
||||
onPress={() => toast.error('Media view is not available yet...')}
|
||||
// onPress={() => (getExplorerStore().layoutMode = 'media')}
|
||||
>
|
||||
<MonitorPlay
|
||||
color={tw.color(
|
||||
store.layoutMode === 'media'
|
||||
? 'text-accent'
|
||||
: 'text-ink-dull'
|
||||
)}
|
||||
size={23}
|
||||
/>
|
||||
</Pressable>
|
||||
</View>
|
||||
<SortByMenu />
|
||||
</View>
|
||||
</MotiView>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
);
|
||||
};
|
||||
export default Menu;
|
|
@ -15,8 +15,8 @@ const sortOptions = {
|
|||
|
||||
type SortByType = keyof typeof sortOptions;
|
||||
|
||||
const ArrowUpIcon = () => <ArrowUp weight="bold" size={16} color={tw.color('ink')} />;
|
||||
const ArrowDownIcon = () => <ArrowDown weight="bold" size={16} color={tw.color('ink')} />;
|
||||
const ArrowUpIcon = () => <ArrowUp weight="bold" size={16} color={tw.color('ink-dull')} />;
|
||||
const ArrowDownIcon = () => <ArrowDown weight="bold" size={16} color={tw.color('ink-dull')} />;
|
||||
|
||||
const SortByMenu = () => {
|
||||
const [sortBy, setSortBy] = useState<SortByType>('name');
|
||||
|
@ -26,7 +26,7 @@ const SortByMenu = () => {
|
|||
<Menu
|
||||
trigger={
|
||||
<View style={tw`flex flex-row items-center`}>
|
||||
<Text style={tw`mr-0.5 font-medium text-ink`}>{sortOptions[sortBy]}</Text>
|
||||
<Text style={tw`mr-0.5 font-medium text-ink-dull`}>{sortOptions[sortBy]}</Text>
|
||||
{sortDirection === 'asc' ? <ArrowUpIcon /> : <ArrowDownIcon />}
|
||||
</View>
|
||||
}
|
|
@ -150,19 +150,10 @@ const toastErrorSuccess = (
|
|||
) => {
|
||||
return {
|
||||
onError: () => {
|
||||
errorMessage &&
|
||||
toast({
|
||||
type: 'error',
|
||||
text: errorMessage
|
||||
});
|
||||
errorMessage && toast.error(errorMessage);
|
||||
},
|
||||
onSuccess: () => {
|
||||
successMessage &&
|
||||
toast({
|
||||
type: 'success',
|
||||
text: successMessage
|
||||
}),
|
||||
successCallBack?.();
|
||||
successMessage && toast.success(successMessage), successCallBack?.();
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
|
@ -3,25 +3,25 @@ import { Text, View } from 'react-native';
|
|||
import Toast, { ToastConfig } from 'react-native-toast-message';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
|
||||
// TODO:
|
||||
// - Expand toast on press to show full message if it's too long
|
||||
// - Add a onPress option
|
||||
// - Add leading icon & trailing icon
|
||||
const baseStyles = 'w-[340px] flex-row overflow-hidden rounded-md border p-3 shadow-lg';
|
||||
|
||||
const toastConfig: ToastConfig = {
|
||||
success: ({ text1, ...rest }) => (
|
||||
<View
|
||||
style={tw`w-[340px] flex-row overflow-hidden rounded-md border border-app-line bg-app-darkBox/90 p-3 shadow-lg`}
|
||||
>
|
||||
<View style={tw.style(baseStyles, 'border-app-line bg-app-darkBox/90 ')}>
|
||||
<Text style={tw`text-sm font-medium text-ink`} numberOfLines={3}>
|
||||
{text1}
|
||||
</Text>
|
||||
</View>
|
||||
),
|
||||
error: ({ text1, ...rest }) => (
|
||||
<View
|
||||
style={tw`border-app-red bg-app-red/90 w-[340px] flex-row overflow-hidden rounded-md border p-3 shadow-lg`}
|
||||
>
|
||||
<View style={tw.style(baseStyles, 'border-red-500 bg-red-500/90')}>
|
||||
<Text style={tw`text-sm font-medium text-ink`} numberOfLines={3}>
|
||||
{text1}
|
||||
</Text>
|
||||
</View>
|
||||
),
|
||||
info: ({ text1, ...rest }) => (
|
||||
<View style={tw.style(baseStyles, 'border-app-line bg-app-darkBox/90')}>
|
||||
<Text style={tw`text-sm font-medium text-ink`} numberOfLines={3}>
|
||||
{text1}
|
||||
</Text>
|
||||
|
@ -29,8 +29,26 @@ const toastConfig: ToastConfig = {
|
|||
)
|
||||
};
|
||||
|
||||
function toast({ text, type }: { type: 'success' | 'error' | 'info'; text: string }) {
|
||||
Toast.show({ type, text1: text, visibilityTime: 3000, topOffset: 60 });
|
||||
function showToast({ text, type }: { type: 'success' | 'error' | 'info'; text: string }) {
|
||||
const visibilityTime = 3000;
|
||||
const topOffset = 60;
|
||||
Toast.show({ type, text1: text, visibilityTime, topOffset });
|
||||
}
|
||||
|
||||
const toast: {
|
||||
success: (text: string) => void;
|
||||
error: (text: string) => void;
|
||||
info: (text: string) => void;
|
||||
} = {
|
||||
success: function (text: string): void {
|
||||
showToast({ text, type: 'success' });
|
||||
},
|
||||
error: function (text: string): void {
|
||||
showToast({ text, type: 'error' });
|
||||
},
|
||||
info: function (text: string): void {
|
||||
showToast({ text, type: 'info' });
|
||||
}
|
||||
};
|
||||
|
||||
export { Toast, toast, toastConfig };
|
||||
|
|
|
@ -22,9 +22,7 @@ const ListTag = ({ tag, tagStyle }: ListTagProps) => {
|
|||
containerStyle={tw`rounded-md border border-app-cardborder bg-app-card p-3`}
|
||||
enableTrackpadTwoFingerGesture
|
||||
renderRightActions={(progress, _, swipeable) => (
|
||||
<>
|
||||
<RightActions progress={progress} swipeable={swipeable} tag={tag} />
|
||||
</>
|
||||
<RightActions progress={progress} swipeable={swipeable} tag={tag} />
|
||||
)}
|
||||
>
|
||||
<View style={twStyle('h-auto flex-row items-center justify-between', tagStyle)}>
|
||||
|
@ -41,7 +39,7 @@ const ListTag = ({ tag, tagStyle }: ListTagProps) => {
|
|||
{tag.name}
|
||||
</Text>
|
||||
</View>
|
||||
<Pressable hitSlop={24} onPress={() => swipeRef.current?.openRight()}>
|
||||
<Pressable onPress={() => swipeRef.current?.openRight()}>
|
||||
<DotsThreeOutlineVertical
|
||||
weight="fill"
|
||||
size={20}
|
||||
|
|
|
@ -1,22 +1,7 @@
|
|||
import { CheckCircle } from 'phosphor-react-native';
|
||||
import React from 'react';
|
||||
import { useLibraryQuery } from '@sd/client';
|
||||
import { PulseAnimation } from '~/components/animation/lottie';
|
||||
import BrowseCategories from '~/components/browse/BrowseCategories';
|
||||
import BrowseLocations from '~/components/browse/BrowseLocations';
|
||||
import BrowseTags from '~/components/browse/BrowseTags';
|
||||
import Jobs from '~/components/browse/Jobs';
|
||||
import ScreenContainer from '~/components/layout/ScreenContainer';
|
||||
import { tw } from '~/lib/tailwind';
|
||||
|
||||
function JobIcon() {
|
||||
const { data: isActive } = useLibraryQuery(['jobs.isActive']);
|
||||
return isActive ? (
|
||||
<PulseAnimation style={tw`h-[24px] w-[32px]`} speed={1.5} />
|
||||
) : (
|
||||
<CheckCircle color="white" size={24} />
|
||||
);
|
||||
}
|
||||
|
||||
export default function BrowseScreen() {
|
||||
return (
|
||||
|
@ -24,7 +9,6 @@ export default function BrowseScreen() {
|
|||
<BrowseCategories />
|
||||
<BrowseLocations />
|
||||
<BrowseTags />
|
||||
<Jobs />
|
||||
</ScreenContainer>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -18,12 +18,13 @@ interface Props {
|
|||
}
|
||||
|
||||
export default function TagsScreen({ viewStyle = 'list' }: Props) {
|
||||
const tags = useLibraryQuery(['tags.list']);
|
||||
const navigation = useNavigation<BrowseStackScreenProps<'Browse'>['navigation']>();
|
||||
const modalRef = useRef<ModalRef>(null);
|
||||
|
||||
const tags = useLibraryQuery(['tags.list']);
|
||||
useNodes(tags.data?.nodes);
|
||||
const tagData = useCache(tags.data?.items);
|
||||
|
||||
return (
|
||||
<ScreenContainer scrollview={false} style={tw`relative px-6 py-0`}>
|
||||
<Pressable
|
||||
|
|
|
@ -42,7 +42,7 @@ const EditLocationSettingsScreen = ({
|
|||
onSuccess: () => {
|
||||
form.reset(form.getValues());
|
||||
queryClient.invalidateQueries(['locations.list']);
|
||||
toast({ type: 'success', text: 'Location updated!' });
|
||||
toast.success('Location updated!');
|
||||
// TODO: navigate back & reset input focus!
|
||||
}
|
||||
});
|
||||
|
|
|
@ -34,7 +34,7 @@ const LibraryGeneralSettingsScreen = (_: SettingsStackScreenProps<'LibraryGenera
|
|||
useAutoForm(form, (value) => {
|
||||
editLibrary({ description: value.description, name: value.name, id: library.uuid });
|
||||
// console.log('Updated', value);
|
||||
toast({ type: 'success', text: 'Library updated!' });
|
||||
toast.success('Library updated!');
|
||||
});
|
||||
|
||||
return (
|
||||
|
|
|
@ -25,23 +25,20 @@ export function flattenThumbnailKey(thumbKey: string[]) {
|
|||
return thumbKey.join('/');
|
||||
}
|
||||
|
||||
const explorerStore = proxy({
|
||||
const store = proxy({
|
||||
...state,
|
||||
reset: () => resetStore(explorerStore, state),
|
||||
reset: () => resetStore(store, state),
|
||||
addNewThumbnail: (thumbKey: string[]) => {
|
||||
explorerStore.newThumbnails.add(flattenThumbnailKey(thumbKey));
|
||||
store.newThumbnails.add(flattenThumbnailKey(thumbKey));
|
||||
},
|
||||
// this should be done when the explorer query is refreshed
|
||||
// prevents memory leak
|
||||
resetNewThumbnails: () => {
|
||||
explorerStore.newThumbnails.clear();
|
||||
store.newThumbnails.clear();
|
||||
}
|
||||
});
|
||||
|
||||
export function useExplorerStore() {
|
||||
return useSnapshot(explorerStore);
|
||||
}
|
||||
|
||||
export function getExplorerStore() {
|
||||
return explorerStore;
|
||||
}
|
||||
/** for reading */
|
||||
export const useExplorerStore = () => useSnapshot(store);
|
||||
/** for writing */
|
||||
export const getExplorerStore = () => store;
|
||||
|
|
|
@ -3,14 +3,15 @@ import { proxy, ref, useSnapshot } from 'valtio';
|
|||
import { ExplorerItem } from '@sd/client';
|
||||
import { ModalRef } from '~/components/layout/Modal';
|
||||
|
||||
export const actionsModalStore = proxy({
|
||||
const store = proxy({
|
||||
modalRef: ref(createRef<ModalRef>()),
|
||||
data: null as ExplorerItem | null,
|
||||
setData: (data: ExplorerItem) => {
|
||||
actionsModalStore.data = data;
|
||||
store.data = data;
|
||||
}
|
||||
});
|
||||
|
||||
export function useActionsModalStore() {
|
||||
return useSnapshot(actionsModalStore);
|
||||
}
|
||||
/** for reading */
|
||||
export const useActionsModalStore = () => useSnapshot(store);
|
||||
/** for writing */
|
||||
export const getActionsModalStore = () => store;
|
||||
|
|
|
@ -161,10 +161,7 @@ const searchStore = proxy<
|
|||
}
|
||||
});
|
||||
|
||||
export function useSearchStore() {
|
||||
return useSnapshot(searchStore);
|
||||
}
|
||||
|
||||
export function getSearchStore() {
|
||||
return searchStore;
|
||||
}
|
||||
/** for reading */
|
||||
export const useSearchStore = () => useSnapshot(searchStore);
|
||||
/** for writing */
|
||||
export const getSearchStore = () => searchStore;
|
||||
|
|
Loading…
Reference in a new issue