mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-04-21 23:18:06 -04:00
* search options start * small progress * more * bunch of stuff * semi functioning filters * cleanup setup api * progress * remove filters * hooked up to query epic moment * fix * move db stuff to specific modules * in/notIn for some fields * generate ts * big gains * working filter options for locations, tags and kind * working search query * perfect fixed filters * saved searches lol * merge error * saved searches via api * better routing * [ENG-1338] Fix fresh Spacedrive install failing to start due to attempting to query a nonexistent Library (#1649) Fix Spacedrive failing to start due to attempting to query a nonexistent Library - Rename useShoudRedirect to useRedirectToNewLocations - Improve behaviour for the immedite redirection after adding a new location * Show hidden files false by default (#1652) bool * fix remove filter in list * tweaks * fix nav buttons * unify MediaData search handling * cleanup saved search writing * Add left top bar portals for tags and search + fixed media view on tags * added search to filter dropdown * render cycle improvements * hotfix * wip * Refactor with Brendan, but this is a WIP and the search query no longer works Co-authored-by: Brendan Allan <Brendonovich@users.noreply.github.com> * progress * fix location/$id page * fix tags too Co-authored-by: Brendan Allan <Brendonovich@users.noreply.github.com> * 3rd refactor lol epic style * half-done with enum-ification of SearchFilterArgs * broken fixed filters but working inNotIn filters * search name + extension kinda working * hidden filter * fixed filters working?? * deferred search value * extensions works * filtered search items mostly working * tweaks * stacked approach working for non-search filters * move to Explorer/Search * actually use filterArgs in queries things actually work properly now * added new icons from Mint * goof * cleanup types, filters and mutation logic * actually use search value * remove overview from sidebar * don't shrink LibrariesDropdown ga * remove overview from sidebar and default to /network --------- Co-authored-by: Brendan Allan <brendonovich@outlook.com> Co-authored-by: Vítor Vasconcellos <vasconcellos.dev@gmail.com> Co-authored-by: Brendan Allan <Brendonovich@users.noreply.github.com>
171 lines
3.7 KiB
TypeScript
171 lines
3.7 KiB
TypeScript
'use client';
|
|
|
|
import * as RadixDM from '@radix-ui/react-dropdown-menu';
|
|
import clsx from 'clsx';
|
|
import React, {
|
|
ContextType,
|
|
createContext,
|
|
PropsWithChildren,
|
|
ReactNode,
|
|
Suspense,
|
|
useCallback,
|
|
useContext,
|
|
useRef,
|
|
useState
|
|
} from 'react';
|
|
import { Link } from 'react-router-dom';
|
|
|
|
import {
|
|
contextMenuClassNames,
|
|
ContextMenuDivItem,
|
|
contextMenuItemClassNames,
|
|
ContextMenuItemProps,
|
|
contextMenuSeparatorClassNames
|
|
} from './ContextMenu';
|
|
|
|
interface DropdownMenuProps
|
|
extends RadixDM.MenuContentProps,
|
|
Pick<RadixDM.DropdownMenuProps, 'onOpenChange'> {
|
|
trigger: React.ReactNode;
|
|
triggerClassName?: string;
|
|
alignToTrigger?: boolean;
|
|
}
|
|
|
|
const DropdownMenuContext = createContext<boolean | null>(null);
|
|
|
|
export const useDropdownMenuContext = <T extends boolean>({ suspense }: { suspense?: T } = {}) => {
|
|
const ctx = useContext(DropdownMenuContext);
|
|
|
|
if (suspense && ctx === null) throw new Error('DropdownMenuContext.Provider not found!');
|
|
|
|
return ctx as T extends true
|
|
? NonNullable<ContextType<typeof DropdownMenuContext>>
|
|
: NonNullable<ContextType<typeof DropdownMenuContext>> | undefined;
|
|
};
|
|
|
|
const Root = (props: PropsWithChildren<DropdownMenuProps>) => {
|
|
const {
|
|
alignToTrigger,
|
|
onOpenChange,
|
|
trigger,
|
|
triggerClassName,
|
|
asChild = true,
|
|
className,
|
|
children,
|
|
...contentProps
|
|
} = props;
|
|
|
|
const [width, setWidth] = useState<number>();
|
|
|
|
const measureRef = useCallback(
|
|
(ref: HTMLButtonElement | null) => {
|
|
alignToTrigger && ref && setWidth(ref.getBoundingClientRect().width);
|
|
},
|
|
[alignToTrigger]
|
|
);
|
|
|
|
return (
|
|
<RadixDM.Root onOpenChange={onOpenChange}>
|
|
<RadixDM.Trigger ref={measureRef} className={triggerClassName} asChild={asChild}>
|
|
{trigger}
|
|
</RadixDM.Trigger>
|
|
<RadixDM.Portal>
|
|
<Suspense fallback={null}>
|
|
<RadixDM.Content
|
|
className={clsx(contextMenuClassNames, width && '!min-w-0', className)}
|
|
align="start"
|
|
style={{ width }}
|
|
{...contentProps}
|
|
>
|
|
<DropdownMenuContext.Provider value={true}>
|
|
{children}
|
|
</DropdownMenuContext.Provider>
|
|
</RadixDM.Content>
|
|
</Suspense>
|
|
</RadixDM.Portal>
|
|
</RadixDM.Root>
|
|
);
|
|
};
|
|
|
|
const Separator = (props: { className?: string }) => (
|
|
<RadixDM.Separator className={clsx(contextMenuSeparatorClassNames, props.className)} />
|
|
);
|
|
|
|
const SubMenu = ({
|
|
label,
|
|
icon,
|
|
iconProps,
|
|
keybind,
|
|
variant,
|
|
className,
|
|
...props
|
|
}: RadixDM.MenuSubContentProps & ContextMenuItemProps & { trigger?: ReactNode }) => {
|
|
return (
|
|
<RadixDM.Sub>
|
|
<RadixDM.SubTrigger className={contextMenuItemClassNames}>
|
|
{props.trigger || (
|
|
<ContextMenuDivItem
|
|
rightArrow
|
|
{...{ label, icon, iconProps, keybind, variant }}
|
|
/>
|
|
)}
|
|
</RadixDM.SubTrigger>
|
|
<RadixDM.Portal>
|
|
<Suspense fallback={null}>
|
|
<RadixDM.SubContent
|
|
className={clsx(contextMenuClassNames, className)}
|
|
{...props}
|
|
/>
|
|
</Suspense>
|
|
</RadixDM.Portal>
|
|
</RadixDM.Sub>
|
|
);
|
|
};
|
|
|
|
interface DropdownItemProps extends ContextMenuItemProps {
|
|
to?: string;
|
|
selected?: boolean;
|
|
}
|
|
|
|
const Item = ({
|
|
icon,
|
|
iconProps,
|
|
label,
|
|
children,
|
|
keybind,
|
|
variant,
|
|
className,
|
|
selected,
|
|
to,
|
|
...props
|
|
}: DropdownItemProps & RadixDM.MenuItemProps) => {
|
|
const ref = useRef<HTMLDivElement>(null);
|
|
|
|
const renderInner = (
|
|
// to style this, pass in variant
|
|
<ContextMenuDivItem
|
|
// className={clsx(selected && 'bg-accent text-white')}
|
|
{...{ icon, iconProps, label, keybind, variant, children }}
|
|
/>
|
|
);
|
|
|
|
return (
|
|
<RadixDM.Item ref={ref} className={clsx(contextMenuItemClassNames, className)} {...props}>
|
|
{to ? (
|
|
<Link to={to} onClick={() => ref.current?.click()}>
|
|
{renderInner}
|
|
</Link>
|
|
) : (
|
|
renderInner
|
|
)}
|
|
</RadixDM.Item>
|
|
);
|
|
};
|
|
|
|
export const DropdownMenu = {
|
|
Root,
|
|
Item,
|
|
Separator,
|
|
SubMenu
|
|
};
|