Files
spacedrive/interface/app/$libraryId/Layout/Sidebar/LibrarySection.tsx
Jamie Pine 10a10c56ad [ENG-944] Sidebar UX Improvements (#1270)
* - added local section to sidebar
- added spacedrop screen, showing local peers
- added placeholder network screen
-removed unused swift package
- created a watcher for system volumes to invalidate ui when drives are added/removed

* clouds

* fix more imports

* see more

* open location if volume is location

* gen assets

* remove log

* [ENG-939, ENG-1173] PDF Thumbnails (#1242)

* sd-pdf

* Process PDF blocking render inside a spawn_blocking
 - Load a single global Pdfium instance

* Migrate pdf thumb logic to sd-images
 - Replace block_in_place with spawn_blocking
 - Only load LibHeif once
 - Allow thumbnailer (both indexed and non-indexed locations) to process documents
 - Disable loading pdf viewer in Inspection in favour of loading it's thumbnail

* Try to load pdfium lib from absolute path

* Revert removed import due to rebase

* Small nitpick and some warnings

---------

Co-authored-by: Ericson Fogo Soares <ericson.ds999@gmail.com>

* [ENG-888] Media view should show current folder downward (#1437)

* Done but ugly

* layout

* Now with a select

---------

Co-authored-by: ameer2468 <33054370+ameer2468@users.noreply.github.com>

* add cool folder thing to inspector + stuff

* fix text color

* fix lock

* fix typescript

* fix ts

---------

Co-authored-by: Utku Bakir <74243531+utkubakir@users.noreply.github.com>
Co-authored-by: Vítor Vasconcellos <vasconcellos.dev@gmail.com>
Co-authored-by: Ericson Fogo Soares <ericson.ds999@gmail.com>
Co-authored-by: ameer2468 <33054370+ameer2468@users.noreply.github.com>
Co-authored-by: Brendan Allan <brendonovich@outlook.com>
2023-10-09 10:11:23 +00:00

225 lines
5.7 KiB
TypeScript

import { EjectSimple } from '@phosphor-icons/react';
import { Laptop, Mobile, Server } from '@sd/assets/icons';
import clsx from 'clsx';
import { useEffect, useState } from 'react';
import { Link, NavLink } from 'react-router-dom';
import {
arraysEqual,
useBridgeQuery,
useDebugState,
useFeatureFlag,
useLibraryQuery,
useOnlineLocations
} from '@sd/client';
import { Button, Tooltip } from '@sd/ui';
import { AddLocationButton } from '~/app/$libraryId/settings/library/locations/AddLocationButton';
import { Folder, SubtleButton } from '~/components';
import SidebarLink from './Link';
import LocationsContextMenu from './LocationsContextMenu';
import Section from './Section';
import SeeMore from './SeeMore';
import TagsContextMenu from './TagsContextMenu';
type SidebarGroup = {
name: string;
items: SidebarItem[];
};
type SidebarItem = {
name: string;
icon: React.ReactNode;
to: string;
position: number;
};
type TriggeredContextItem =
| {
type: 'location';
locationId: number;
}
| {
type: 'tag';
tagId: number;
};
const EjectButton = ({ className }: { className?: string }) => (
<Button className={clsx('absolute right-[2px] !p-[5px]', className)} variant="subtle">
<EjectSimple weight="bold" size={18} className="h-3 w-3 opacity-70" />
</Button>
);
export const LibrarySection = () => {
const debugState = useDebugState();
const node = useBridgeQuery(['nodeState']);
const locationsQuery = useLibraryQuery(['locations.list'], { keepPreviousData: true });
const tags = useLibraryQuery(['tags.list'], { keepPreviousData: true });
const onlineLocations = useOnlineLocations();
const isPairingEnabled = useFeatureFlag('p2pPairing');
const [triggeredContextItem, setTriggeredContextItem] = useState<TriggeredContextItem | null>(
null
);
const [seeMoreLocations, setSeeMoreLocations] = useState(false);
useEffect(() => {
const outsideClick = () => {
document.addEventListener('click', () => {
setTriggeredContextItem(null);
});
};
outsideClick();
return () => {
document.removeEventListener('click', outsideClick);
};
}, [triggeredContextItem]);
return (
<>
<Section
name="Devices"
actionArea={
isPairingEnabled && (
<Link to="settings/library/nodes">
<SubtleButton />
</Link>
)
}
>
{node.data && (
<>
<SidebarLink
className="group relative w-full"
to={`node/${node.data.id}`}
key={node.data.id}
>
<img src={Laptop} className="mr-1 h-5 w-5" />
<span className="truncate">{node.data.name}</span>
</SidebarLink>
{/* {debugState.enabled && (
<>
<SidebarLink
className="group relative w-full"
to={`node/23`}
key={23}
>
<img src={Mobile} className="mr-1 h-5 w-5" />
<span className="truncate">Spacephone</span>
</SidebarLink>
<SidebarLink
className="group relative w-full"
to={`node/24`}
key={24}
>
<img src={Server} className="mr-1 h-5 w-5" />
<span className="truncate">Titan</span>
</SidebarLink>
</>
)} */}
</>
)}
<Tooltip
label="Coming soon! This alpha release doesn't include library sync, it will be ready very soon."
tooltipClassName="bg-black"
position="right"
>
<Button disabled variant="dotted" className="mt-1 w-full">
Add Device
</Button>
</Tooltip>
</Section>
<Section
name="Locations"
actionArea={
<Link to="settings/library/locations">
<SubtleButton />
</Link>
}
>
<SeeMore
items={locationsQuery.data || []}
renderItem={(location, index) => (
<LocationsContextMenu key={location.id} locationId={location.id}>
<SidebarLink
onContextMenu={() =>
setTriggeredContextItem({
type: 'location',
locationId: location.id
})
}
className={clsx(
triggeredContextItem?.type === 'location' &&
triggeredContextItem.locationId === location.id
? 'border-accent'
: 'border-transparent',
'group relative w-full border'
)}
to={`location/${location.id}`}
>
<div className="relative -mt-0.5 mr-1 shrink-0 grow-0">
<Folder size={18} />
<div
className={clsx(
'absolute bottom-0.5 right-0 h-1.5 w-1.5 rounded-full',
onlineLocations.some((l) =>
arraysEqual(location.pub_id, l)
)
? 'bg-green-500'
: 'bg-red-500'
)}
/>
</div>
<span className="truncate">{location.name}</span>
</SidebarLink>
</LocationsContextMenu>
)}
/>
<AddLocationButton className="mt-1" />
</Section>
{!!tags.data?.length && (
<Section
name="Tags"
actionArea={
<NavLink to="settings/library/tags">
<SubtleButton />
</NavLink>
}
>
<SeeMore
items={tags.data}
renderItem={(tag, index) => (
<TagsContextMenu tagId={tag.id} key={tag.id}>
<SidebarLink
onContextMenu={() =>
setTriggeredContextItem({
type: 'tag',
tagId: tag.id
})
}
className={clsx(
triggeredContextItem?.type === 'tag' &&
triggeredContextItem?.tagId === tag.id
? 'border-accent'
: 'border-transparent',
'border'
)}
to={`tag/${tag.id}`}
>
<div
className="h-[12px] w-[12px] shrink-0 rounded-full"
style={{ backgroundColor: tag.color || '#efefef' }}
/>
<span className="ml-1.5 truncate text-sm">{tag.name}</span>
</SidebarLink>
</TagsContextMenu>
)}
/>
</Section>
)}
</>
);
};