mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-13 08:24:04 +00:00
storage bar changes/file kinds loader
This commit is contained in:
parent
4735adcb66
commit
45e54f33ee
|
@ -5,7 +5,7 @@ import { motion } from 'framer-motion';
|
||||||
import React, { MouseEventHandler, useCallback, useEffect, useRef, useState } from 'react';
|
import React, { MouseEventHandler, useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import { useNavigate } from 'react-router';
|
import { useNavigate } from 'react-router';
|
||||||
import { KindStatistic, uint32ArrayToBigInt, useLibraryQuery } from '@sd/client';
|
import { KindStatistic, uint32ArrayToBigInt, useLibraryQuery } from '@sd/client';
|
||||||
import { Card, Tooltip } from '@sd/ui';
|
import { Card, Loader, Tooltip } from '@sd/ui';
|
||||||
import { useIsDark, useLocale } from '~/hooks';
|
import { useIsDark, useLocale } from '~/hooks';
|
||||||
|
|
||||||
const INFO_ICON_CLASSLIST =
|
const INFO_ICON_CLASSLIST =
|
||||||
|
@ -71,7 +71,7 @@ const FileKindStats: React.FC<FileKindStatsProps> = () => {
|
||||||
const isDark = useIsDark();
|
const isDark = useIsDark();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { t } = useLocale();
|
const { t } = useLocale();
|
||||||
const { data } = useLibraryQuery(['library.kindStatistics']);
|
const { data, isLoading } = useLibraryQuery(['library.kindStatistics']);
|
||||||
const [fileKinds, setFileKinds] = useState<FileKind[]>([]);
|
const [fileKinds, setFileKinds] = useState<FileKind[]>([]);
|
||||||
const [cardWidth, setCardWidth] = useState<number>(0);
|
const [cardWidth, setCardWidth] = useState<number>(0);
|
||||||
const containerRef = useRef<HTMLDivElement>(null);
|
const containerRef = useRef<HTMLDivElement>(null);
|
||||||
|
@ -182,90 +182,110 @@ const FileKindStats: React.FC<FileKindStatsProps> = () => {
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
className="max-w-1/2 group mx-1 flex h-[220px] w-full min-w-[400px] shrink-0 flex-col gap-2 bg-app-box/50"
|
className="max-w-1/2 group mx-1 flex h-[220px] w-full min-w-[400px] shrink-0 flex-col gap-2 bg-app-box/50"
|
||||||
>
|
>
|
||||||
<div className={TOTAL_FILES_CLASSLIST}>
|
{isLoading ? (
|
||||||
<Tooltip className="flex items-center" label={t('bar_graph_info')}>
|
<>
|
||||||
<div className="flex items-center gap-2">
|
<div className="m-auto flex flex-col items-center justify-center gap-5">
|
||||||
<span
|
<Loader />
|
||||||
className={clsx(
|
<p className="text-m font-medium text-ink-faint">
|
||||||
'text-xl font-black',
|
Calculating file kinds...
|
||||||
isDark ? 'text-white' : 'text-black'
|
</p>
|
||||||
)}
|
</div>
|
||||||
>
|
</>
|
||||||
{data?.total_identified_files
|
) : (
|
||||||
? formatNumberWithCommas(data.total_identified_files)
|
<>
|
||||||
: '0'}{' '}
|
<div className={TOTAL_FILES_CLASSLIST}>
|
||||||
</span>
|
<Tooltip className="flex items-center" label={t('bar_graph_info')}>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center gap-2">
|
||||||
{t('total_files')}
|
<span
|
||||||
<Info weight="fill" className={INFO_ICON_CLASSLIST} />
|
className={clsx(
|
||||||
|
'text-xl font-black',
|
||||||
|
isDark ? 'text-white' : 'text-black'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{data?.total_identified_files
|
||||||
|
? formatNumberWithCommas(data.total_identified_files)
|
||||||
|
: '0'}{' '}
|
||||||
|
</span>
|
||||||
|
<div className="flex items-center">
|
||||||
|
{t('total_files')}
|
||||||
|
<Info weight="fill" className={INFO_ICON_CLASSLIST} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
<div className={UNIDENTIFIED_FILES_CLASSLIST}>
|
||||||
|
<Tooltip label={t('unidentified_files_info')}>
|
||||||
|
<span>
|
||||||
|
{data?.total_unidentified_files
|
||||||
|
? formatNumberWithCommas(data.total_unidentified_files)
|
||||||
|
: '0'}{' '}
|
||||||
|
unidentified files
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
<div className={BARS_CONTAINER_CLASSLIST}>
|
||||||
<div className={UNIDENTIFIED_FILES_CLASSLIST}>
|
{sortedFileKinds.map((fileKind, index) => {
|
||||||
<Tooltip label={t('unidentified_files_info')}>
|
const iconImage = iconsRef.current[fileKind.kind];
|
||||||
<span>
|
const barColor = interpolateHexColor(
|
||||||
{data?.total_unidentified_files
|
BAR_COLOR_START,
|
||||||
? formatNumberWithCommas(data.total_unidentified_files)
|
BAR_COLOR_END,
|
||||||
: '0'}{' '}
|
index / (barCount - 1)
|
||||||
unidentified files
|
);
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className={BARS_CONTAINER_CLASSLIST}>
|
|
||||||
{sortedFileKinds.map((fileKind, index) => {
|
|
||||||
const iconImage = iconsRef.current[fileKind.kind];
|
|
||||||
const barColor = interpolateHexColor(
|
|
||||||
BAR_COLOR_START,
|
|
||||||
BAR_COLOR_END,
|
|
||||||
index / (barCount - 1)
|
|
||||||
);
|
|
||||||
|
|
||||||
const barHeight =
|
const barHeight =
|
||||||
mapFractionalValue(fileKind.count, maxFileCount, BAR_MAX_HEIGHT) + 'px';
|
mapFractionalValue(
|
||||||
return (
|
fileKind.count,
|
||||||
<>
|
maxFileCount,
|
||||||
<Tooltip
|
BAR_MAX_HEIGHT
|
||||||
asChild
|
) + 'px';
|
||||||
key={fileKind.kind}
|
return (
|
||||||
label={
|
<>
|
||||||
formatNumberWithCommas(fileKind.count) +
|
<Tooltip
|
||||||
' ' +
|
asChild
|
||||||
fileKind.kind +
|
key={fileKind.kind}
|
||||||
's'
|
label={
|
||||||
}
|
formatNumberWithCommas(fileKind.count) +
|
||||||
position="left"
|
' ' +
|
||||||
>
|
fileKind.kind +
|
||||||
<div
|
's'
|
||||||
className="relative flex w-full min-w-8 max-w-10 grow cursor-pointer flex-col items-center"
|
}
|
||||||
onDoubleClick={makeBarClickHandler(fileKind)}
|
position="left"
|
||||||
>
|
>
|
||||||
{iconImage && (
|
<div
|
||||||
<img
|
className="relative flex w-full min-w-8 max-w-10 grow cursor-pointer flex-col items-center"
|
||||||
src={iconImage.src}
|
onDoubleClick={makeBarClickHandler(fileKind)}
|
||||||
alt={fileKind.kind}
|
>
|
||||||
className="relative mb-1 size-4 duration-500"
|
{iconImage && (
|
||||||
/>
|
<img
|
||||||
)}
|
src={iconImage.src}
|
||||||
<motion.div
|
alt={fileKind.kind}
|
||||||
className="flex w-full flex-col items-center rounded transition-all duration-500"
|
className="relative mb-1 size-4 duration-500"
|
||||||
initial={{ height: 0 }}
|
/>
|
||||||
animate={{ height: barHeight }}
|
)}
|
||||||
transition={{ duration: 0.4, ease: [0.42, 0, 0.58, 1] }}
|
<motion.div
|
||||||
style={{
|
className="flex w-full flex-col items-center rounded transition-all duration-500"
|
||||||
height: barHeight,
|
initial={{ height: 0 }}
|
||||||
backgroundColor: barColor
|
animate={{ height: barHeight }}
|
||||||
}}
|
transition={{
|
||||||
></motion.div>
|
duration: 0.4,
|
||||||
</div>
|
ease: [0.42, 0, 0.58, 1]
|
||||||
</Tooltip>
|
}}
|
||||||
<div className="sm col-span-1 row-start-2 row-end-auto text-center text-[10px] font-medium text-ink-faint">
|
style={{
|
||||||
{formatCount(fileKind.count)}
|
height: barHeight,
|
||||||
</div>
|
backgroundColor: barColor
|
||||||
</>
|
}}
|
||||||
);
|
></motion.div>
|
||||||
})}
|
</div>
|
||||||
</div>
|
</Tooltip>
|
||||||
|
<div className="sm col-span-1 row-start-2 row-end-auto text-center text-[10px] font-medium text-ink-faint">
|
||||||
|
{formatCount(fileKind.count)}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -86,18 +86,18 @@ const LibraryStats = () => {
|
||||||
|
|
||||||
const StatItemNames: Partial<Record<keyof Statistics, string>> = {
|
const StatItemNames: Partial<Record<keyof Statistics, string>> = {
|
||||||
total_library_bytes: t('library_bytes'),
|
total_library_bytes: t('library_bytes'),
|
||||||
total_local_bytes_capacity: t('total_bytes_capacity'),
|
|
||||||
total_local_bytes_free: t('total_bytes_free'),
|
|
||||||
library_db_size: t('library_db_size'),
|
library_db_size: t('library_db_size'),
|
||||||
total_library_preview_media_bytes: t('preview_media_bytes')
|
total_library_preview_media_bytes: t('preview_media_bytes'),
|
||||||
|
total_local_bytes_capacity: t('total_bytes_capacity'),
|
||||||
|
total_local_bytes_free: t('total_bytes_free')
|
||||||
};
|
};
|
||||||
|
|
||||||
const StatDescriptions: Partial<Record<keyof Statistics, string>> = {
|
const StatDescriptions: Partial<Record<keyof Statistics, string>> = {
|
||||||
total_library_bytes: t('library_bytes_description'),
|
total_library_bytes: t('library_bytes_description'),
|
||||||
total_local_bytes_capacity: t('total_bytes_capacity_description'),
|
|
||||||
total_local_bytes_free: t('total_bytes_free_description'),
|
|
||||||
library_db_size: t('library_db_size_description'),
|
library_db_size: t('library_db_size_description'),
|
||||||
total_library_preview_media_bytes: t('preview_media_bytes_description')
|
total_library_preview_media_bytes: t('preview_media_bytes_description'),
|
||||||
|
total_local_bytes_capacity: t('total_bytes_capacity_description'),
|
||||||
|
total_local_bytes_free: t('total_bytes_free_description')
|
||||||
};
|
};
|
||||||
|
|
||||||
const displayableStatItems = Object.keys(
|
const displayableStatItems = Object.keys(
|
||||||
|
@ -113,6 +113,7 @@ const LibraryStats = () => {
|
||||||
const totalUsedSpace = Number(statistics.total_local_bytes_used);
|
const totalUsedSpace = Number(statistics.total_local_bytes_used);
|
||||||
|
|
||||||
// Define the major categories and aggregate the "Other" category
|
// Define the major categories and aggregate the "Other" category
|
||||||
|
// TODO: edit to use library size as total capacity and split bar into major categories without system data
|
||||||
const majorCategories = ['Document', 'Text', 'Image', 'Video'];
|
const majorCategories = ['Document', 'Text', 'Image', 'Video'];
|
||||||
const aggregatedData = (storageBarData ?? []).reduce(
|
const aggregatedData = (storageBarData ?? []).reduce(
|
||||||
(acc, curr) => {
|
(acc, curr) => {
|
||||||
|
@ -165,7 +166,7 @@ const LibraryStats = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="flex h-[220px] w-[750px] shrink-0 flex-col bg-app-box/50">
|
<Card className="flex h-[220px] w-[750px] shrink-0 flex-col bg-app-box/50">
|
||||||
<div className="mb-1 flex overflow-hidden p-4">
|
<div className="flex overflow-hidden p-4">
|
||||||
{Object.entries(statistics)
|
{Object.entries(statistics)
|
||||||
.sort(
|
.sort(
|
||||||
([a], [b]) =>
|
([a], [b]) =>
|
||||||
|
|
|
@ -3,7 +3,7 @@ import { humanizeSize } from '@sd/client';
|
||||||
import { Tooltip } from '@sd/ui';
|
import { Tooltip } from '@sd/ui';
|
||||||
import { useIsDark } from '~/hooks';
|
import { useIsDark } from '~/hooks';
|
||||||
|
|
||||||
const BARWIDTH = 700;
|
const BARWIDTH = 750;
|
||||||
|
|
||||||
const lightenColor = (color: string, percent: number) => {
|
const lightenColor = (color: string, percent: number) => {
|
||||||
const num = parseInt(color.replace('#', ''), 16);
|
const num = parseInt(color.replace('#', ''), 16);
|
||||||
|
@ -109,7 +109,7 @@ const StorageBar: React.FC<StorageBarProps> = ({ sections, totalSpace }) => {
|
||||||
{sections.map((section, index) => (
|
{sections.map((section, index) => (
|
||||||
<Tooltip key={index} label={section.tooltip} position="top">
|
<Tooltip key={index} label={section.tooltip} position="top">
|
||||||
<div
|
<div
|
||||||
className="mb-2 mr-6 flex items-center"
|
className="mb-2 mr-8 flex items-center"
|
||||||
onMouseEnter={() => setHoveredSectionIndex(index)}
|
onMouseEnter={() => setHoveredSectionIndex(index)}
|
||||||
onMouseLeave={() => setHoveredSectionIndex(null)}
|
onMouseLeave={() => setHoveredSectionIndex(null)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -715,7 +715,7 @@
|
||||||
"toggle_sidebar": "تبديل الشريط الجانبي",
|
"toggle_sidebar": "تبديل الشريط الجانبي",
|
||||||
"tools": "أدوات",
|
"tools": "أدوات",
|
||||||
"total_bytes_capacity": "Total capacity",
|
"total_bytes_capacity": "Total capacity",
|
||||||
"total_bytes_capacity_description": "The total capacity of all nodes connected to the library. May show incorrect values during alpha.",
|
"total_bytes_capacity_description": "The total capacity of the current nodes connected to the library. May show incorrect values during alpha.",
|
||||||
"total_bytes_free": "Free space",
|
"total_bytes_free": "Free space",
|
||||||
"total_bytes_free_description": "Free space available on all nodes connected to the library.",
|
"total_bytes_free_description": "Free space available on all nodes connected to the library.",
|
||||||
"total_bytes_used": "Total used space",
|
"total_bytes_used": "Total used space",
|
||||||
|
|
|
@ -707,10 +707,10 @@
|
||||||
"toggle_quick_preview": "Toggle quick preview",
|
"toggle_quick_preview": "Toggle quick preview",
|
||||||
"toggle_sidebar": "Toggle sidebar",
|
"toggle_sidebar": "Toggle sidebar",
|
||||||
"tools": "Tools",
|
"tools": "Tools",
|
||||||
"total_bytes_capacity": "Total capacity",
|
"total_bytes_capacity": "Total local capacity",
|
||||||
"total_bytes_capacity_description": "The total capacity of all nodes connected to the library. May show incorrect values during alpha.",
|
"total_bytes_capacity_description": "The total capacity the current node. May show incorrect values during alpha.",
|
||||||
"total_bytes_free": "Free space",
|
"total_bytes_free": "Free local space",
|
||||||
"total_bytes_free_description": "Free space available on all nodes connected to the library.",
|
"total_bytes_free_description": "Free space available on the current node.",
|
||||||
"total_bytes_used": "Total used space",
|
"total_bytes_used": "Total used space",
|
||||||
"total_bytes_used_description": "Total space used on all nodes connected to the library.",
|
"total_bytes_used_description": "Total space used on all nodes connected to the library.",
|
||||||
"total_files": "Total files",
|
"total_files": "Total files",
|
||||||
|
|
Loading…
Reference in a new issue