[ENG-1317] Ephemeral location notice (#1628)

* wip

* ephemeral notice
This commit is contained in:
nikec
2023-10-20 06:11:54 +02:00
committed by GitHub
parent b827f9cc66
commit d8ac61eeba
3 changed files with 138 additions and 4 deletions

View File

@@ -1,3 +1,7 @@
import { ArrowLeft, ArrowRight, Info } from '@phosphor-icons/react';
import * as Dialog from '@radix-ui/react-dialog';
import { iconNames } from '@sd/assets/util';
import clsx from 'clsx';
import { memo, Suspense, useDeferredValue, useMemo } from 'react';
import {
ExplorerItem,
@@ -5,9 +9,16 @@ import {
useLibraryQuery,
type EphemeralPathOrder
} from '@sd/client';
import { Tooltip } from '@sd/ui';
import { Button, Tooltip } from '@sd/ui';
import { PathParamsSchema, type PathParams } from '~/app/route-schemas';
import { useOperatingSystem, useZodSearchParams } from '~/hooks';
import { Icon } from '~/components';
import {
getDismissibleNoticeStore,
useDismissibleNoticeStore,
useIsDark,
useOperatingSystem,
useZodSearchParams
} from '~/hooks';
import Explorer from './Explorer';
import { ExplorerContextProvider } from './Explorer/Context';
@@ -19,7 +30,125 @@ import {
import { DefaultTopBarOptions } from './Explorer/TopBarOptions';
import { useExplorer, useExplorerSettings } from './Explorer/useExplorer';
import { AddLocationButton } from './settings/library/locations/AddLocationButton';
import { TOP_BAR_HEIGHT } from './TopBar';
import { TopBarPortal } from './TopBar/Portal';
import TopBarButton from './TopBar/TopBarButton';
const NOTICE_ITEMS: { icon: keyof typeof iconNames; name: string }[] = [
{
icon: 'Folder',
name: 'Documents'
},
{
icon: 'Archive',
name: 'Keep-Safe'
},
{
icon: 'Executable',
name: 'Spacedrive'
},
{
icon: 'Folder',
name: 'Music'
}
];
const EphemeralNotice = ({ path }: { path: string }) => {
const isDark = useIsDark();
const { ephemeral: dismissed } = useDismissibleNoticeStore();
const dismiss = () => (getDismissibleNoticeStore().ephemeral = true);
return (
<Dialog.Root
open={!dismissed}
onOpenChange={(open) => (getDismissibleNoticeStore().ephemeral = !open)}
>
<Dialog.Portal>
<Dialog.Overlay className="fixed inset-0 z-50 bg-app/80 backdrop-blur-sm radix-state-closed:animate-out radix-state-closed:fade-out-0 radix-state-open:animate-in radix-state-open:fade-in-0" />
<Dialog.Content className="fixed left-[50%] top-[50%] z-50 w-96 translate-x-[-50%] translate-y-[-50%] overflow-hidden rounded-md border border-app-line bg-app shadow-lg outline-none duration-200 radix-state-closed:animate-out radix-state-closed:fade-out-0 radix-state-closed:zoom-out-95 radix-state-closed:slide-out-to-left-1/2 radix-state-closed:slide-out-to-top-[48%] radix-state-open:animate-in radix-state-open:fade-in-0 radix-state-open:zoom-in-95 radix-state-open:slide-in-from-left-1/2 radix-state-open:slide-in-from-top-[48%]">
<div className="relative flex aspect-video overflow-hidden border-b border-app-line/50 bg-gradient-to-b from-app-darkBox to-app to-80% pl-5 pt-5">
<div
className={clsx(
'relative flex flex-1 flex-col overflow-hidden rounded-tl-lg border-l border-t border-app-line/75 bg-app shadow-lg',
isDark ? 'shadow-app-shade/40' : 'shadow-app-shade/20'
)}
>
<div className="absolute inset-0 z-50 bg-app/80 backdrop-blur-[2px]" />
<div
style={{ height: TOP_BAR_HEIGHT }}
className="flex items-center gap-3.5 border-b border-sidebar-divider px-3.5"
>
<div className="flex">
<TopBarButton rounding="left">
<ArrowLeft size={14} className="m-[4px]" weight="bold" />
</TopBarButton>
<TopBarButton rounding="right" disabled>
<ArrowRight size={14} className="m-[4px]" weight="bold" />
</TopBarButton>
</div>
<Tooltip
label="Add path as an indexed location"
className="z-50 w-max min-w-0 shrink animate-pulse [animation-duration:_3000ms] hover:animate-none"
>
<AddLocationButton
path={path}
className="shadow-md"
onClick={dismiss}
/>
</Tooltip>
</div>
<div className="relative flex-1">
<div className="absolute inset-0 grid w-[115%] grid-cols-4 gap-3 pl-3 pt-3">
{NOTICE_ITEMS.map((item) => (
<div key={item.name} className="flex flex-col items-center">
<Icon name={item.icon} draggable={false} />
<span className="text-center text-xs font-medium text-ink">
{item.name}
</span>
</div>
))}
</div>
</div>
</div>
<div className="absolute inset-x-0 bottom-0 z-50 h-4 bg-gradient-to-t from-app/70 to-transparent" />
</div>
<div className="p-3 pt-0">
<div className="py-4 text-center">
<h2 className="text-lg font-semibold text-ink">Local Locations</h2>
<p className="mt-px text-sm text-ink-dull">
Browse your files and folders directly from your device.
</p>
</div>
<div className="flex items-center rounded-md border border-app-line bg-app-box px-3 py-2 text-ink-faint">
<Info size={20} weight="light" className="mr-2.5 shrink-0" />
<p className="text-sm font-light">
Consider indexing your local locations for a faster and more
efficient exploration.
</p>
</div>
<Button
variant="accent"
className="mt-3 w-full !rounded"
size="md"
onClick={dismiss}
>
Got it
</Button>
</div>
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
};
const EphemeralExplorer = memo((props: { args: PathParams }) => {
const os = useOperatingSystem();
@@ -106,6 +235,7 @@ export const Component = () => {
return (
<Suspense>
<EphemeralNotice path={path.path ?? ''} />
<EphemeralExplorer args={path} />
</Suspense>
);

View File

@@ -11,9 +11,10 @@ import { openDirectoryPickerDialog } from './openDirectoryPickerDialog';
interface AddLocationButton extends ButtonProps {
path?: string;
onClick?: () => void;
}
export const AddLocationButton = ({ path, className, ...props }: AddLocationButton) => {
export const AddLocationButton = ({ path, className, onClick, ...props }: AddLocationButton) => {
const platform = usePlatform();
const transition = {
type: 'keyframes',
@@ -50,6 +51,8 @@ export const AddLocationButton = ({ path, className, ...props }: AddLocationButt
dialogManager.create((dp) => (
<AddLocationDialog path={path ?? ''} {...dp} />
));
onClick?.();
}}
{...props}
>

View File

@@ -4,7 +4,8 @@ import { valtioPersist } from '@sd/client';
export const dismissibleNoticeStore = valtioPersist('dismissible-notice', {
mediaView: false,
gridView: false,
listView: false
listView: false,
ephemeral: false
});
export function useDismissibleNoticeStore() {