mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-04 13:23:28 +00:00
added picharts to location cards and refactored
This commit is contained in:
parent
585ee12336
commit
91860b8b13
90
interface/app/$libraryId/overview/DeviceCard.tsx
Normal file
90
interface/app/$libraryId/overview/DeviceCard.tsx
Normal file
|
@ -0,0 +1,90 @@
|
|||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { humanizeSize } from '@sd/client';
|
||||
import { Card, CircularProgress, tw } from '@sd/ui';
|
||||
import { Icon } from '~/components';
|
||||
import { useIsDark, useLocale } from '~/hooks';
|
||||
import StatCard from './StatCard';
|
||||
|
||||
type StatCardProps = {
|
||||
name: string;
|
||||
icon: string;
|
||||
totalSpace: string | number[];
|
||||
freeSpace?: string | number[];
|
||||
color: string;
|
||||
connectionType: 'lan' | 'p2p' | 'cloud' | null;
|
||||
};
|
||||
|
||||
|
||||
|
||||
const Pill = tw.div`px-1.5 py-[1px] rounded text-tiny font-medium text-ink-dull bg-app-box border border-app-line`;
|
||||
|
||||
const DeviceCard = ({ icon, name, connectionType, ...stats }: StatCardProps) => {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
const isDark = useIsDark();
|
||||
|
||||
const { totalSpace, freeSpace, usedSpaceSpace } = useMemo(() => {
|
||||
const totalSpace = humanizeSize(stats.totalSpace);
|
||||
const freeSpace = stats.freeSpace == null ? totalSpace : humanizeSize(stats.freeSpace);
|
||||
return {
|
||||
totalSpace,
|
||||
freeSpace,
|
||||
usedSpaceSpace: humanizeSize(totalSpace.bytes - freeSpace.bytes)
|
||||
};
|
||||
}, [stats]);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
const progress = useMemo(() => {
|
||||
if (!mounted || totalSpace.bytes === 0n) return 0;
|
||||
return Math.floor((usedSpaceSpace.value / totalSpace.value) * 100);
|
||||
}, [mounted, totalSpace, usedSpaceSpace]);
|
||||
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<StatCard body={
|
||||
<div className="flex flex-row items-center gap-5 p-4 px-6">
|
||||
<div className="flex flex-1 flex-col overflow-hidden ">
|
||||
|
||||
<Icon className="-ml-1" name={icon as any} size={60} />
|
||||
<span className="truncate font-medium">{name}</span>
|
||||
<span className="mt-1 truncate text-tiny text-ink-faint">
|
||||
{freeSpace.value}
|
||||
{freeSpace.unit} {' ' + t('free_of') + ' ' + totalSpace.value + ' ' + totalSpace.unit}
|
||||
</span>
|
||||
</div>
|
||||
<div className=' flex items-center justify-center'>
|
||||
<CircularProgress
|
||||
radius={40}
|
||||
progress={progress}
|
||||
strokeWidth={6}
|
||||
trackStrokeWidth={6}
|
||||
strokeColor={progress > 90 ? '#E14444' : '#2599FF'}
|
||||
fillColor="transparent"
|
||||
trackStrokeColor={isDark ? '#252631' : '#efefef'}
|
||||
strokeLinecap="square"
|
||||
className="flex items-center justify-center"
|
||||
transition="stroke-dashoffset 1s ease 0s, stroke 1s ease"
|
||||
>
|
||||
<div className="absolute text-lg font-semibold">
|
||||
{usedSpaceSpace.value}
|
||||
<span className="">
|
||||
{usedSpaceSpace.unit}
|
||||
</span>
|
||||
</div>
|
||||
</CircularProgress>
|
||||
</div>
|
||||
</div>
|
||||
} footer= {
|
||||
<Pill className="uppercase">{connectionType || t('local')}</Pill>
|
||||
|
||||
}>
|
||||
|
||||
</StatCard>
|
||||
);
|
||||
};
|
||||
|
||||
export default DeviceCard;
|
|
@ -1,46 +1,78 @@
|
|||
import { ReactComponent as Ellipsis } from '@sd/assets/svgs/ellipsis.svg';
|
||||
import { useMemo } from 'react';
|
||||
import { humanizeSize } from '@sd/client';
|
||||
import { Button, Card, tw } from '@sd/ui';
|
||||
import { tw } from '@sd/ui';
|
||||
import { Icon } from '~/components';
|
||||
import { Link } from 'react-router-dom';
|
||||
import PieChart from './PieChart';
|
||||
import StatCard from './StatCard';
|
||||
import LocationMenu from './LocationMenu';
|
||||
import { useLocale } from '~/hooks';
|
||||
|
||||
type LocationCardProps = {
|
||||
name: string;
|
||||
icon: string;
|
||||
locationId: number;
|
||||
totalSpace: string | number[];
|
||||
freeSpace?: string | number[];
|
||||
color: string;
|
||||
connectionType: 'lan' | 'p2p' | 'cloud' | null;
|
||||
link?: string;
|
||||
};
|
||||
|
||||
const data = [
|
||||
{ label: 'Category 1', value: 72 },
|
||||
{ label: 'Category 2', value: 50 },
|
||||
{ label: 'Category 3', value: 89 },
|
||||
{ label: 'Category 4', value: 50 },
|
||||
{ label: 'Category 5', value: 15 }
|
||||
];
|
||||
|
||||
const colors = ['#0079E7', '#3F57B0', '#6D35D9', '#9621FF', '#BC13FF'];
|
||||
|
||||
const Pill = tw.div`px-1.5 py-[1px] rounded text-tiny font-medium text-ink-dull bg-app-box border border-app-line`;
|
||||
|
||||
const LocationCard = ({ icon, name, connectionType, ...stats }: LocationCardProps) => {
|
||||
const { totalSpace } = useMemo(() => {
|
||||
return {
|
||||
totalSpace: humanizeSize(stats.totalSpace)
|
||||
};
|
||||
}, [stats]);
|
||||
const HoverPill = tw(Pill)`
|
||||
transition duration-300 ease-in-out
|
||||
hover:bg-[#353347] hover:cursor-pointer
|
||||
`;
|
||||
|
||||
const LocationCard = ({ icon, name, connectionType, link, locationId, ...stats }: LocationCardProps) => {
|
||||
const totalSpace = humanizeSize(stats.totalSpace);
|
||||
const { t } = useLocale();
|
||||
return (
|
||||
<Card className="flex w-[280px] shrink-0 flex-col bg-app-box/50 !p-0 ">
|
||||
<div className="flex flex-row items-center gap-5 p-4 px-6 ">
|
||||
<div className="flex flex-col overflow-hidden">
|
||||
<StatCard
|
||||
body={
|
||||
<div className="flex flex-row items-center gap-5 p-4 px-6">
|
||||
<div className="flex flex-1 flex-col overflow-hidden ">
|
||||
<Icon className="-ml-1" name={icon as any} size={60} />
|
||||
<span className="truncate font-medium">{name}</span>
|
||||
<span className="mt-1 truncate text-tiny text-ink-faint">
|
||||
{totalSpace.value}
|
||||
{totalSpace.unit}
|
||||
Users/matthewyung/applications
|
||||
</span>
|
||||
</div>
|
||||
<div className=' flex items-center justify-center'>
|
||||
<PieChart
|
||||
data={data}
|
||||
radius={40}
|
||||
innerRadius={32}
|
||||
strokeWidth={0}
|
||||
colors={colors}
|
||||
units={totalSpace.unit}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex h-10 flex-row items-center gap-1.5 border-t border-app-line px-2">
|
||||
<Pill className="uppercase">{connectionType || 'Local'}</Pill>
|
||||
<div className="grow" />
|
||||
<Button size="icon" variant="outline">
|
||||
<Ellipsis className="size-3 opacity-50" />
|
||||
</Button>
|
||||
</div>
|
||||
</Card>
|
||||
}
|
||||
footer={
|
||||
<>
|
||||
<Pill className="uppercase">{connectionType || t('local')}</Pill>
|
||||
<div className="ml-auto flex items-center gap-1.5">
|
||||
<Link to={link}>
|
||||
<HoverPill className="opacity-0 group-hover/open:opacity-100">OPEN</HoverPill>
|
||||
</Link>
|
||||
<LocationMenu id={locationId}></LocationMenu>
|
||||
</div>
|
||||
</>
|
||||
}>
|
||||
</StatCard>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
144
interface/app/$libraryId/overview/PieChart.tsx
Normal file
144
interface/app/$libraryId/overview/PieChart.tsx
Normal file
|
@ -0,0 +1,144 @@
|
|||
import React, { useState, useEffect, useRef, FunctionComponent } from 'react';
|
||||
import clsx from 'clsx';
|
||||
|
||||
export type PieChartProps = {
|
||||
data: { label: string; value: number }[];
|
||||
radius: number;
|
||||
strokeWidth?: number;
|
||||
innerRadius?: number;
|
||||
colors?: string[];
|
||||
className?: string;
|
||||
units?: string;
|
||||
};
|
||||
|
||||
const polarToCartesian = (centerX: number, centerY: number, radius: number, angleInDegrees: number) => {
|
||||
const angleInRadians = ((angleInDegrees - 90) * Math.PI) / 180.0;
|
||||
return {
|
||||
x: centerX + radius * Math.cos(angleInRadians),
|
||||
y: centerY + radius * Math.sin(angleInRadians),
|
||||
};
|
||||
};
|
||||
|
||||
const PieChart: FunctionComponent<PieChartProps> = ({
|
||||
data,
|
||||
radius,
|
||||
strokeWidth = 2,
|
||||
innerRadius = 0,
|
||||
colors = ['indianred', 'lightblue', 'lightgreen', 'lightcoral', 'lightgoldenrodyellow'],
|
||||
className = '',
|
||||
units = '',
|
||||
}) => {
|
||||
const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
|
||||
const pieChartRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const handleMouseOut = (event: MouseEvent) => {
|
||||
if (pieChartRef.current && !pieChartRef.current.contains(event.target as Node)) {
|
||||
setHoveredIndex(null);
|
||||
}
|
||||
};
|
||||
|
||||
document.addEventListener('mouseout', handleMouseOut);
|
||||
return () => {
|
||||
document.removeEventListener('mouseout', handleMouseOut);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const total = data.reduce((sum, item) => sum + item.value, 0);
|
||||
const margin = 10;
|
||||
const svgSize = 2 * (radius + strokeWidth) + margin * 2;
|
||||
const center = radius + strokeWidth + margin;
|
||||
|
||||
const renderSlices = () => {
|
||||
let cumulativeValue = 0;
|
||||
|
||||
return data.map((item, index) => {
|
||||
const sliceAngle = (item.value / total) * 360;
|
||||
const startAngle = (cumulativeValue / total) * 360;
|
||||
cumulativeValue += item.value;
|
||||
|
||||
const isHovered = index === hoveredIndex;
|
||||
const middleAngle = startAngle + sliceAngle / 2;
|
||||
const translationDistance = sliceAngle > 50 ? 5 : 10;
|
||||
const translation = polarToCartesian(0, 0, translationDistance, middleAngle);
|
||||
const outerStart = polarToCartesian(center, center, radius, startAngle);
|
||||
const outerEnd = polarToCartesian(center, center, radius, startAngle + sliceAngle);
|
||||
const innerStart = polarToCartesian(center, center, innerRadius!, startAngle + sliceAngle);
|
||||
const innerEnd = polarToCartesian(center, center, innerRadius!, startAngle);
|
||||
const largeArcFlag = sliceAngle > 180 ? 1 : 0;
|
||||
|
||||
const outerPathData = [
|
||||
`M ${outerStart.x} ${outerStart.y}`,
|
||||
`A ${radius} ${radius} 0 ${largeArcFlag} 1 ${outerEnd.x} ${outerEnd.y}`,
|
||||
`L ${center} ${center}`,
|
||||
`Z`,
|
||||
].join(' ');
|
||||
|
||||
const innerPathData = [
|
||||
`M ${innerStart.x} ${innerStart.y}`,
|
||||
`A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 0 ${innerEnd.x} ${innerEnd.y}`,
|
||||
`L ${center} ${center}`,
|
||||
`Z`,
|
||||
].join(' ');
|
||||
|
||||
const fullPathData = [
|
||||
`M ${outerStart.x} ${outerStart.y}`,
|
||||
`A ${radius} ${radius} 0 ${largeArcFlag} 1 ${outerEnd.x} ${outerEnd.y}`,
|
||||
`L ${innerEnd.x} ${innerEnd.y}`,
|
||||
`A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 0 ${innerStart.x} ${innerStart.y}`,
|
||||
`Z`,
|
||||
].join(' ');
|
||||
|
||||
return (
|
||||
<g
|
||||
key={index}
|
||||
onMouseOver={() => setHoveredIndex(index)}
|
||||
onMouseOut={() => setHoveredIndex(null)}
|
||||
className={clsx('transition-transform duration-300 ease-out', {
|
||||
'opacity-100': isHovered,
|
||||
'opacity-50': hoveredIndex !== null && !isHovered,
|
||||
})}
|
||||
style={{
|
||||
transform: isHovered ? `translate(${translation.x}px, ${translation.y}px) scale(1.05)` : 'scale(1)',
|
||||
opacity: hoveredIndex !== null && !isHovered ? 0.5 : 1,
|
||||
transition: 'transform 0.3s ease-out, opacity 0.3s ease-out',
|
||||
zIndex: isHovered ? 10 : 1,
|
||||
}}
|
||||
>
|
||||
{/* Full path for the whole slice, used for hover effect */}
|
||||
<path d={fullPathData} fill="transparent" />
|
||||
{/* Path for the outer portion of the slice, with color */}
|
||||
<path d={outerPathData} fill={colors[index % colors.length]} />
|
||||
</g>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div ref={pieChartRef} className="relative inline-block">
|
||||
<div
|
||||
className={clsx('relative', className)}
|
||||
style={{ width: `${svgSize}px`, height: `${svgSize}px` }}
|
||||
>
|
||||
<svg width={svgSize} height={svgSize} viewBox={`0 0 ${svgSize} ${svgSize}`}>
|
||||
{renderSlices()}
|
||||
{hoveredIndex !== null && (
|
||||
<text
|
||||
x={center}
|
||||
y={center}
|
||||
textAnchor="middle"
|
||||
dominantBaseline="central"
|
||||
className="pointer-events-none text-lg font-bold transition-opacity duration-300 ease-out"
|
||||
style={{ zIndex: 10 }}
|
||||
>
|
||||
{data[hoveredIndex]?.value}
|
||||
<tspan className="ml-0.5 text-tiny text-ink-faint">{units}</tspan>
|
||||
</text>
|
||||
)}
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default PieChart;
|
|
@ -1,95 +1,36 @@
|
|||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { humanizeSize } from '@sd/client';
|
||||
import { Card, CircularProgress, tw } from '@sd/ui';
|
||||
import { Icon } from '~/components';
|
||||
import { useIsDark, useLocale } from '~/hooks';
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { useEffect, useState } from 'react';
|
||||
import { Card, tw } from '@sd/ui';
|
||||
type StatCardProps = {
|
||||
name: string;
|
||||
icon: string;
|
||||
totalSpace: string | number[];
|
||||
freeSpace?: string | number[];
|
||||
color: string;
|
||||
connectionType: 'lan' | 'p2p' | 'cloud' | null;
|
||||
link?: string;
|
||||
devices?: boolean;
|
||||
right?: React.ReactNode;
|
||||
body: React.ReactNode;
|
||||
footer: React.ReactNode;
|
||||
};
|
||||
|
||||
|
||||
const data = [
|
||||
{ label: 'Category 1', value: 72 },
|
||||
{ label: 'Category 2', value: 50 },
|
||||
{ label: 'Category 3', value: 89 },
|
||||
{ label: 'Category 4', value: 50 },
|
||||
{ label: 'Category 5', value: 15 }
|
||||
];
|
||||
|
||||
const colors = ['#0079E7', '#3F57B0', '#6D35D9', '#9621FF', '#BC13FF'];
|
||||
|
||||
|
||||
const Pill = tw.div`px-1.5 py-[1px] rounded text-tiny font-medium text-ink-dull bg-app-box border border-app-line`;
|
||||
|
||||
const StatCard = ({ icon, name, right, connectionType, link, devices, ...stats }: StatCardProps) => {
|
||||
const StatCard = ({ body, footer }: StatCardProps) => {
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
const isDark = useIsDark();
|
||||
|
||||
const { totalSpace, freeSpace, usedSpaceSpace } = useMemo(() => {
|
||||
const totalSpace = humanizeSize(stats.totalSpace);
|
||||
const freeSpace = stats.freeSpace == null ? totalSpace : humanizeSize(stats.freeSpace);
|
||||
return {
|
||||
totalSpace,
|
||||
freeSpace,
|
||||
usedSpaceSpace: humanizeSize(totalSpace.bytes - freeSpace.bytes)
|
||||
};
|
||||
}, [stats]);
|
||||
|
||||
useEffect(() => {
|
||||
setMounted(true);
|
||||
}, []);
|
||||
|
||||
const progress = useMemo(() => {
|
||||
if (!mounted || totalSpace.bytes === 0n) return 0;
|
||||
return Math.floor((usedSpaceSpace.value / totalSpace.value) * 100);
|
||||
}, [mounted, totalSpace, usedSpaceSpace]);
|
||||
|
||||
const { t } = useLocale();
|
||||
|
||||
return (
|
||||
<Card className="flex w-[280px] shrink-0 flex-col bg-app-box/50 !p-0">
|
||||
<div className="flex flex-row items-center gap-5 p-4 px-6">
|
||||
{stats.freeSpace && (
|
||||
<CircularProgress
|
||||
radius={40}
|
||||
progress={progress}
|
||||
strokeWidth={6}
|
||||
trackStrokeWidth={6}
|
||||
strokeColor={progress > 90 ? '#E14444' : '#2599FF'}
|
||||
fillColor="transparent"
|
||||
trackStrokeColor={isDark ? '#252631' : '#efefef'}
|
||||
strokeLinecap="square"
|
||||
className="flex items-center justify-center"
|
||||
transition="stroke-dashoffset 1s ease 0s, stroke 1s ease"
|
||||
>
|
||||
<div className="absolute text-lg font-semibold">
|
||||
{usedSpaceSpace.value}
|
||||
<span className="ml-0.5 text-tiny opacity-60">
|
||||
{usedSpaceSpace.unit}
|
||||
</span>
|
||||
</div>
|
||||
</CircularProgress>
|
||||
)}
|
||||
<div className="flex flex-col overflow-hidden">
|
||||
<Icon className="-ml-1" name={icon as any} size={60} />
|
||||
<span className="truncate font-medium">{name}</span>
|
||||
<span className="mt-1 truncate text-tiny text-ink-faint">
|
||||
{freeSpace.value}
|
||||
{freeSpace.unit} {devices && ' ' + t('free_of') + ' ' + totalSpace.value + ' ' + totalSpace.unit}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<Card className="group/open flex w-[280px] shrink-0 flex-col bg-app-box/50 !p-0">
|
||||
{body}
|
||||
<div className="flex h-10 flex-row items-center gap-1.5 border-t border-app-line px-2">
|
||||
<Pill className="uppercase">{connectionType || t('local')}</Pill>
|
||||
<div className="ml-auto flex items-center gap-1.5">
|
||||
{right && link && <Link
|
||||
to={link}
|
||||
className="mx-1 rounded border px-2 text-xs font-medium transition duration-300 ease-in-out"
|
||||
>
|
||||
Open
|
||||
</Link>}
|
||||
{right}
|
||||
|
||||
</div>
|
||||
{footer}
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
|
|
|
@ -12,9 +12,11 @@ import OverviewSection from './Layout/Section';
|
|||
import LibraryStatistics from './LibraryStats';
|
||||
import NewCard from './NewCard';
|
||||
import StatisticItem from './StatCard';
|
||||
import LocationMenu from './LocationMenu';
|
||||
import LocationCard from './LocationCard';
|
||||
import DeviceCard from './DeviceCard';
|
||||
|
||||
export const Component = () => {
|
||||
|
||||
useRouteTitle('Overview');
|
||||
const os = useOperatingSystem();
|
||||
|
||||
|
@ -43,33 +45,6 @@ export const Component = () => {
|
|||
center={<SearchBar redirectToSearch />}
|
||||
right={
|
||||
os === 'windows' && <TopBarOptions />
|
||||
// <TopBarOptions
|
||||
// options={[
|
||||
// [
|
||||
// {
|
||||
// toolTipLabel: 'Spacedrop',
|
||||
// onClick: () => {},
|
||||
// icon: <Broadcast className={TOP_BAR_ICON_STYLE} />,
|
||||
// individual: true,
|
||||
// showAtResolution: 'sm:flex'
|
||||
// },
|
||||
// {
|
||||
// toolTipLabel: 'Key Manager',
|
||||
// onClick: () => {},
|
||||
// icon: <Key className={TOP_BAR_ICON_STYLE} />,
|
||||
// individual: true,
|
||||
// showAtResolution: 'sm:flex'
|
||||
// },
|
||||
// {
|
||||
// toolTipLabel: 'Overview Display Settings',
|
||||
// onClick: () => {},
|
||||
// icon: <SlidersHorizontal className={TOP_BAR_ICON_STYLE} />,
|
||||
// individual: true,
|
||||
// showAtResolution: 'sm:flex'
|
||||
// }
|
||||
// ]
|
||||
// ]}
|
||||
// />
|
||||
}
|
||||
/>
|
||||
<div className="mt-4 flex flex-col gap-3 pt-3">
|
||||
|
@ -81,7 +56,7 @@ export const Component = () => {
|
|||
</OverviewSection>
|
||||
<OverviewSection count={1} title={t('devices')}>
|
||||
{node && (
|
||||
<StatisticItem
|
||||
<DeviceCard
|
||||
name={node.name}
|
||||
icon={hardwareModelToIcon(node.device_model as any)}
|
||||
totalSpace={
|
||||
|
@ -90,49 +65,8 @@ export const Component = () => {
|
|||
connectionType={null}
|
||||
freeSpace={stats.data?.statistics?.total_local_bytes_free || '0'}
|
||||
color="#0362FF"
|
||||
devices={true}
|
||||
/>
|
||||
)}
|
||||
{/* <StatisticItem
|
||||
name="Jamie's MacBook"
|
||||
icon="Laptop"
|
||||
total_space="4098046511104"
|
||||
free_space="969004651119"
|
||||
color="#0362FF"
|
||||
connection_type="p2p"
|
||||
/>
|
||||
<StatisticItem
|
||||
name="Jamie's iPhone"
|
||||
icon="Mobile"
|
||||
total_space="500046511104"
|
||||
free_space="39006511104"
|
||||
color="#0362FF"
|
||||
connection_type="p2p"
|
||||
/>
|
||||
<StatisticItem
|
||||
name="Titan NAS"
|
||||
icon="Server"
|
||||
total_space="60000046511104"
|
||||
free_space="43000046511104"
|
||||
color="#0362FF"
|
||||
connection_type="p2p"
|
||||
/>
|
||||
<StatisticItem
|
||||
name="Jamie's iPad"
|
||||
icon="Tablet"
|
||||
total_space="1074077906944"
|
||||
free_space="121006553275"
|
||||
color="#0362FF"
|
||||
connection_type="lan"
|
||||
/>
|
||||
<StatisticItem
|
||||
name="Jamie's Air"
|
||||
icon="Laptop"
|
||||
total_space="4098046511104"
|
||||
free_space="969004651119"
|
||||
color="#0362FF"
|
||||
connection_type="p2p"
|
||||
/> */}
|
||||
<NewCard
|
||||
icons={['Laptop', 'Server', 'SilverBox', 'Tablet']}
|
||||
text={t('connect_device_description')}
|
||||
|
@ -144,18 +78,17 @@ export const Component = () => {
|
|||
|
||||
<OverviewSection count={locations.length} title={t('locations')}>
|
||||
{locations?.map((item) => (
|
||||
<StatisticItem
|
||||
<LocationCard
|
||||
key={item.id}
|
||||
locationId={item.id}
|
||||
name={item.name || t('unnamed_location')}
|
||||
icon="Folder"
|
||||
totalSpace={item.size_in_bytes || [0]}
|
||||
color="#0362FF"
|
||||
connectionType={null}
|
||||
link={`../location/${item.id}`}
|
||||
right={
|
||||
<LocationMenu id={item.id}></LocationMenu>
|
||||
}
|
||||
/>
|
||||
link={`../location/${item.id}`}>
|
||||
</LocationCard>
|
||||
|
||||
))}
|
||||
{!locations?.length && (
|
||||
<NewCard
|
||||
|
@ -167,22 +100,6 @@ export const Component = () => {
|
|||
</OverviewSection>
|
||||
|
||||
<OverviewSection count={0} title={t('cloud_drives')}>
|
||||
{/* <StatisticItem
|
||||
name="James Pine"
|
||||
icon="DriveDropbox"
|
||||
total_space="104877906944"
|
||||
free_space="074877906944"
|
||||
color="#0362FF"
|
||||
connection_type="cloud"
|
||||
/>
|
||||
<StatisticItem
|
||||
name="Spacedrive S3"
|
||||
icon="DriveAmazonS3"
|
||||
total_space="1074877906944"
|
||||
free_space="704877906944"
|
||||
color="#0362FF"
|
||||
connection_type="cloud"
|
||||
/> */}
|
||||
|
||||
<NewCard
|
||||
icons={[
|
||||
|
@ -196,22 +113,6 @@ export const Component = () => {
|
|||
// buttonText={t('connect_cloud)}
|
||||
/>
|
||||
</OverviewSection>
|
||||
|
||||
{/* <OverviewSection title="Locations">
|
||||
<div className="flex flex-row gap-2">
|
||||
{locations.map((location) => (
|
||||
<div
|
||||
key={location.id}
|
||||
className="flex w-[100px] flex-col items-center gap-2"
|
||||
>
|
||||
<Icon size={80} name="Folder" />
|
||||
<span className="text-xs font-medium truncate">
|
||||
{location.name}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</OverviewSection> */}
|
||||
</div>
|
||||
</div>
|
||||
</SearchContextProvider>
|
||||
|
|
Loading…
Reference in a new issue