redesigned home screen

This commit is contained in:
Jamie Pine 2022-04-25 17:36:22 -07:00
parent 5a1d8fc174
commit edcd011986
6 changed files with 134 additions and 11 deletions

10
docs/product/ideas.md Normal file
View file

@ -0,0 +1,10 @@
# Core view
The primary screen in the Spacedrive app is of your entire virtual network, every "core" is a device under your full command. It is presented in a large panel list view, featuring bold visuals and quick interactions with your fleet.
Recent files, recent locations and settings are part of these panels, that can be customized at will.
Visual indicators report the live status of this device.
Key statistics of this devices are also present on these panels.
A "Core" represents a device in your "Space".

View file

@ -37,6 +37,7 @@
"react-error-boundary": "^3.1.4",
"react-hotkeys-hook": "^3.4.4",
"react-json-view": "^1.21.3",
"react-loading-icons": "^1.0.8",
"react-portal": "^4.2.2",
"react-query": "^3.34.19",
"react-router": "6.3.0",

View file

@ -0,0 +1,89 @@
import {
Desktop,
DeviceMobileCamera,
DotsSixVertical,
Laptop,
Phone,
PhoneX
} from 'phosphor-react';
import React, { useState } from 'react';
import FileItem from '../file/FileItem';
import { Button } from '@sd/ui';
import ProgressBar from '../primitive/ProgressBar';
import { CogIcon } from '@heroicons/react/solid';
import { KeyIcon } from '@heroicons/react/outline';
import LoadingIcons, { Rings } from 'react-loading-icons';
export interface DeviceProps {
name: string;
size: string;
type: 'laptop' | 'desktop' | 'phone';
locations: { name: string }[];
runningJob?: { amount: number; task: string };
}
export function Device(props: DeviceProps) {
const [selectedFile, setSelectedFile] = useState<null | string>(null);
function handleSelect(key: string) {
if (selectedFile === key) setSelectedFile(null);
else setSelectedFile(key);
}
return (
<div className="w-full bg-gray-600 border rounded-md border-gray-550 ">
<div className="flex flex-row items-center px-4 pt-2 pb-2">
<DotsSixVertical weight="bold" className="mr-3 opacity-30" />
{props.type === 'phone' && <DeviceMobileCamera weight="fill" size={20} className="mr-2" />}
{props.type === 'laptop' && <Laptop weight="fill" size={20} className="mr-2" />}
{props.type === 'desktop' && <Desktop weight="fill" size={20} className="mr-2" />}
<h3 className="font-semibold text-md">{props.name}</h3>
<div className="flex flex-row space-x-1.5 mt-0.5">
<span className="font-semibold h-[19px] ml-3 py-0.5 px-1.5 text-[10px] rounded-md text-gray-400 bg-gray-550">
Primary
</span>
<span className="font-semibold h-[19px] py-0.5 px-1.5 text-[10px] rounded-md text-gray-400 bg-gray-550">
{props.size}
</span>
</div>
<div className="flex flex-grow" />
{props.runningJob && (
<div className="flex flex-row ml-5 bg-opacity-50 border border-gray-500 rounded bg-gray-550">
<Rings
stroke="#2599FF"
strokeOpacity={4}
strokeWidth={10}
speed={0.5}
className="ml-0.5 mt-0.5 -mr-1 w-7 h-7"
/>
<div className="flex flex-col p-1.5">
<span className="mb-[3px] -mt-0.5 truncate text-gray-450 text-tiny">
{props.runningJob.task}...
</span>
<ProgressBar value={props.runningJob?.amount} total={100} />
</div>
</div>
)}
<div className="flex flex-row ml-3 space-x-1">
<Button className="!p-1 ">
<KeyIcon className="w-5 h-5" />
</Button>
<Button className="!p-1 ">
<CogIcon className="w-5 h-5" />
</Button>
</div>
</div>
<hr className="border-gray-700" />
<hr className="border-gray-550" />
<div className="px-4 pb-3 mt-3">
{props.locations.map((location) => (
<FileItem
selected={selectedFile == location.name}
onClick={() => handleSelect(location.name)}
fileName={location.name}
folder
/>
))}
</div>
</div>
);
}

View file

@ -31,7 +31,7 @@ export default function FileItem(props: Props) {
className={clsx(
'border-2 border-transparent rounded-lg text-center w-[100px] h-[100px] mb-1',
{
'bg-gray-50 dark:bg-gray-750': props.selected
'bg-gray-50 dark:bg-gray-650': props.selected
}
)}
>

View file

@ -1,4 +1,6 @@
import { DotsSixVertical, Laptop, LineSegments } from 'phosphor-react';
import React, { useState } from 'react';
import { Device } from '../components/device/Device';
import FileItem from '../components/file/FileItem';
interface StatItemProps {
@ -9,7 +11,7 @@ interface StatItemProps {
const StatItem: React.FC<StatItemProps> = (props) => {
return (
<div className="flex flex-col p-4 mt-2 duration-75 transform rounded-md cursor-default hover:bg-gray-50 hover:dark:bg-gray-600">
<div className="flex flex-col px-4 py-3 duration-75 transform rounded-md cursor-default hover:bg-gray-50 hover:dark:bg-gray-600">
<span className="text-sm text-gray-400">{props.name}</span>
<span className="text-2xl font-bold">
{props.value}
@ -23,17 +25,16 @@ export const OverviewScreen: React.FC<{}> = (props) => {
const [selectedFile, setSelectedFile] = useState<null | string>(null);
function handleSelect(key: string) {
// if (selectedFile === key) setSelectedFile(null);
// else setSelectedFile(key);
setSelectedFile(key);
if (selectedFile === key) setSelectedFile(null);
else setSelectedFile(key);
}
return (
<div className="flex flex-col w-full h-screen">
<div data-tauri-drag-region className="flex flex-shrink-0 w-full h-7" />
<div className="flex flex-col w-full h-screen px-5 pb-3 overflow-scroll">
<div className="flex items-center w-full px-2">
<div className="flex flex-wrap space-x-4">
<div className="flex flex-col w-full h-screen px-3 overflow-scroll">
<div className="flex items-center w-full ml-4">
<div className="flex flex-wrap p-2 space-x-6">
<StatItem name="Total capacity" value="26.5" unit="TB" />
<StatItem name="Index size" value="103" unit="MB" />
<StatItem name="Preview media" value="23.5" unit="GB" />
@ -42,9 +43,25 @@ export const OverviewScreen: React.FC<{}> = (props) => {
<StatItem name="Total backed up" value="25.3" unit="TB" />
</div>
</div>
<div className="mt-5" />
<div className="flex flex-col space-y-4">
<Device
name="Spacedad"
size="1.4TB"
runningJob={{ amount: 65, task: 'Generating preview media' }}
locations={[{ name: 'Pictures' }, { name: 'Downloads' }, { name: 'Minecraft' }]}
type="laptop"
/>
<Device
name="Jamies iPhone"
size="47.7GB"
locations={[{ name: 'Camera Roll' }, { name: 'Notes' }]}
type="phone"
/>
</div>
{/* <hr className="my-5 border-gray-50 dark:border-gray-600" /> */}
<hr className="my-5 border-gray-50 dark:border-gray-600" />
<div className="mt-2 space-x-1">
{/* <div className="mt-2 space-x-1">
<FileItem
selected={selectedFile == 'assets'}
onClick={() => handleSelect('assets')}
@ -132,7 +149,7 @@ export const OverviewScreen: React.FC<{}> = (props) => {
folder
/>
</div>
<hr className="my-5 border-gray-50 dark:border-gray-600" />
<hr className="my-5 border-gray-50 dark:border-gray-600" /> */}
{/* <hr className="my-5 dark:border-gray-600" /> */}
</div>

View file

@ -280,6 +280,7 @@ importers:
react-error-boundary: ^3.1.4
react-hotkeys-hook: ^3.4.4
react-json-view: ^1.21.3
react-loading-icons: ^1.0.8
react-portal: ^4.2.2
react-query: ^3.34.19
react-router: 6.3.0
@ -321,6 +322,7 @@ importers:
react-error-boundary: 3.1.4_react@18.0.0
react-hotkeys-hook: 3.4.4_react-dom@18.0.0+react@18.0.0
react-json-view: 1.21.3_761282c47ea27a9f40e1344337910648
react-loading-icons: 1.0.8
react-portal: 4.2.2_react-dom@18.0.0+react@18.0.0
react-query: 3.34.19_react-dom@18.0.0+react@18.0.0
react-router: 6.3.0_react@18.0.0
@ -4834,6 +4836,10 @@ packages:
resolution: {integrity: sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==}
dev: false
/react-loading-icons/1.0.8:
resolution: {integrity: sha512-j0myUwDUPoo3qaPkbgnA7U2RNHqLLC+wXcpMWe+rtk3Iw+mGHltZ3QitPSHFKtsFKlpM9UlMmZGZ6sw6WVVW7w==}
dev: false
/react-portal/4.2.2_react-dom@18.0.0+react@18.0.0:
resolution: {integrity: sha512-vS18idTmevQxyQpnde0Td6ZcUlv+pD8GTyR42n3CHUQq9OHi1C4jDE4ZWEbEsrbrLRhSECYiao58cvocwMtP7Q==}
peerDependencies: