landing prep

This commit is contained in:
Jamie Pine 2022-05-23 03:16:23 -07:00
parent 5175dcbbfb
commit 8356f39737
35 changed files with 149 additions and 194 deletions

View file

@ -88,7 +88,7 @@ export default function AppEmbed() {
/>
)}
{renderImage && <div className="z-40 h-full fade-in-app-embed landing-img " />}
{renderImage && <div className="z-40 h-[300px] sm:h-full fade-in-app-embed landing-img" />}
</div>
</div>
</div>

View file

@ -0,0 +1,9 @@
import React from 'react';
export default function NewBanner () {
return <div className="text-xs sm:text-base fade-in-whats-new px-5 py-1.5 bg-opacity-50 cursor-pointer mb-5 -mt-3 flex flex-row bg-gray-800 hover:bg-gray-750 border border-gray-600 hover:border-gray-550 rounded-full transition">
<span className='truncate text-gray-350'>Spacedrive raises $1.9M lead by OSS Capital</span>
<div className='w-[1px] mx-4 h-22 bg-gray-500' />
<span className='flex-shrink-0 font-semibold text-transparent bg-clip-text bg-gradient-to-r from-primary-400 to-blue-600'>Read post </span>
</div>
}

View file

@ -8,6 +8,7 @@ import AppEmbed from '../components/AppEmbed';
import { Bubbles } from '../components/Bubbles';
import { Footer } from '../components/Footer';
import NavBar from '../components/NavBar';
import NewBanner from '../components/NewBanner';
interface SectionProps {
orientation: 'left' | 'right';
@ -45,14 +46,14 @@ function Page() {
return (
<>
<div className="mt-28 lg:mt-36" />
<NewBanner />
<h1
id="content"
className="z-30 px-2 mb-3 text-4xl font-black leading-tight text-center md:text-6xl"
className="z-30 px-2 mb-3 text-4xl font-black leading-tight text-center fade-in-heading md:text-6xl"
>
A file explorer from the future.
</h1>
<p className="z-30 max-w-4xl mt-1 mb-8 text-center text-md lg:text-lg leading-2 lg:leading-8 text-gray-450">
<p className="z-30 max-w-4xl mt-1 mb-8 text-center animation-delay-1 fade-in-heading text-md lg:text-lg leading-2 lg:leading-8 text-gray-450">
Combine your drives and clouds into one database that you can organize and explore from any
device.
<br />
@ -60,7 +61,15 @@ function Page() {
Designed for creators, hoarders and the painfully disorganized.
</span>
</p>
<div className="flex flex-row space-x-4 delay-3 ">
<div className="z-50 flex flex-row space-x-4 animation-delay-2 fade-in">
<Button
href="https://github.com/spacedriveapp/spacedrive"
target="_blank"
className="z-30 border-0 cursor-pointer bg-opacity-80"
variant="primary"
>
Join Waitlist
</Button>
<Button
href="https://github.com/spacedriveapp/spacedrive"
target="_blank"
@ -71,7 +80,7 @@ function Page() {
Star on GitHub
</Button>
</div>
<p className="z-30 px-6 mt-3 text-sm text-center text-gray-450 ">
<p className="z-30 px-6 mt-3 text-sm text-center text-gray-450 animation-delay-3 fade-in">
Coming soon on macOS, Windows and Linux.
<br />
Shortly after to iOS & Android.

View file

@ -23,18 +23,56 @@ html {
}
.fade-in-heading {
animation: fadeInUp 1s;
animation: fadeInDown 1s forwards;
opacity: 0;
}
.fade-in {
animation: fadeIn 1s forwards;
opacity: 0;
}
.fade-in-whats-new {
animation: fadeInDown 1s forwards;
animation-delay: 2s;
opacity: 0;
}
.animation-delay-1 {
animation-delay: 200ms;
}
.animation-delay-2 {
animation-delay: 500ms;
}
.animation-delay-3 {
animation-delay: 700ms;
}
@keyframes fadeInDown {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
transform: translateY(0px);
opacity: 1;
}
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes fadeInUp {
0% {
opacity: 0;
// transform: translateY(10px);
}
100% {
opacity: 1;
// transform: translateY(0px);
}
}
@ -61,7 +99,7 @@ html {
}
&.bloom-three {
background: conic-gradient(from 90deg at 50% 50%, #2d53c6, #1d054b);
animation-delay: 1100ms;
animation-delay: 1s;
}
}

View file

@ -1,14 +1,2 @@
export type ClientCommand =
| { key: 'FileRead'; params: { id: number } }
| { key: 'FileDelete'; params: { id: number } }
| { key: 'LibDelete'; params: { id: number } }
| { key: 'TagCreate'; params: { name: string; color: string } }
| { key: 'TagUpdate'; params: { name: string; color: string } }
| { key: 'TagAssign'; params: { file_id: number; tag_id: number } }
| { key: 'TagDelete'; params: { id: number } }
| { key: 'LocCreate'; params: { path: string } }
| { key: 'LocUpdate'; params: { id: number; name: string | null } }
| { key: 'LocDelete'; params: { id: number } }
| { key: 'SysVolumeUnmount'; params: { id: number } }
| { key: 'GenerateThumbsForLocation'; params: { id: number; path: string } }
| { key: 'IdentifyUniqueFiles' };
export type ClientCommand = { key: "FileRead", params: { id: number, } } | { key: "FileDelete", params: { id: number, } } | { key: "LibDelete", params: { id: number, } } | { key: "TagCreate", params: { name: string, color: string, } } | { key: "TagUpdate", params: { name: string, color: string, } } | { key: "TagAssign", params: { file_id: number, tag_id: number, } } | { key: "TagDelete", params: { id: number, } } | { key: "LocCreate", params: { path: string, } } | { key: "LocUpdate", params: { id: number, name: string | null, } } | { key: "LocDelete", params: { id: number, } } | { key: "SysVolumeUnmount", params: { id: number, } } | { key: "GenerateThumbsForLocation", params: { id: number, path: string, } } | { key: "IdentifyUniqueFiles" };

View file

@ -1,10 +1,2 @@
export type ClientQuery =
| { key: 'ClientGetState' }
| { key: 'SysGetVolumes' }
| { key: 'LibGetTags' }
| { key: 'JobGetRunning' }
| { key: 'JobGetHistory' }
| { key: 'SysGetLocations' }
| { key: 'SysGetLocation'; params: { id: number } }
| { key: 'LibGetExplorerDir'; params: { location_id: number; path: string; limit: number } }
| { key: 'GetLibraryStatistics' };
export type ClientQuery = { key: "NodeGetState" } | { key: "SysGetVolumes" } | { key: "LibGetTags" } | { key: "JobGetRunning" } | { key: "JobGetHistory" } | { key: "SysGetLocations" } | { key: "SysGetLocation", params: { id: number, } } | { key: "LibGetExplorerDir", params: { location_id: number, path: string, limit: number, } } | { key: "GetLibraryStatistics" } | { key: "GetNodes" };

View file

@ -1,10 +1,4 @@
import type { ClientQuery } from './ClientQuery';
import type { CoreResource } from './CoreResource';
import type { ClientQuery } from "./ClientQuery";
import type { CoreResource } from "./CoreResource";
export type CoreEvent =
| { key: 'InvalidateQuery'; data: ClientQuery }
| { key: 'InvalidateQueryDebounced'; data: ClientQuery }
| { key: 'InvalidateResource'; data: CoreResource }
| { key: 'NewThumbnail'; data: { cas_id: string } }
| { key: 'Log'; data: { message: string } }
| { key: 'DatabaseDisconnected'; data: { reason: string | null } };
export type CoreEvent = { key: "InvalidateQuery", data: ClientQuery } | { key: "InvalidateQueryDebounced", data: ClientQuery } | { key: "InvalidateResource", data: CoreResource } | { key: "NewThumbnail", data: { cas_id: string, } } | { key: "Log", data: { message: string, } } | { key: "DatabaseDisconnected", data: { reason: string | null, } };

View file

@ -1,11 +1,5 @@
import type { File } from './File';
import type { JobReport } from './JobReport';
import type { LocationResource } from './LocationResource';
import type { File } from "./File";
import type { JobReport } from "./JobReport";
import type { LocationResource } from "./LocationResource";
export type CoreResource =
| 'Client'
| 'Library'
| { Location: LocationResource }
| { File: File }
| { Job: JobReport }
| 'Tag';
export type CoreResource = "Client" | "Library" | { Location: LocationResource } | { File: File } | { Job: JobReport } | "Tag";

View file

@ -1,18 +1,8 @@
import type { ClientState } from './ClientState';
import type { DirectoryWithContents } from './DirectoryWithContents';
import type { JobReport } from './JobReport';
import type { LocationResource } from './LocationResource';
import type { Statistics } from './Statistics';
import type { Volume } from './Volume';
import type { DirectoryWithContents } from "./DirectoryWithContents";
import type { JobReport } from "./JobReport";
import type { LocationResource } from "./LocationResource";
import type { NodeState } from "./NodeState";
import type { Statistics } from "./Statistics";
import type { Volume } from "./Volume";
export type CoreResponse =
| { key: 'Success'; data: null }
| { key: 'SysGetVolumes'; data: Array<Volume> }
| { key: 'SysGetLocation'; data: LocationResource }
| { key: 'SysGetLocations'; data: Array<LocationResource> }
| { key: 'LibGetExplorerDir'; data: DirectoryWithContents }
| { key: 'ClientGetState'; data: ClientState }
| { key: 'LocCreate'; data: LocationResource }
| { key: 'JobGetRunning'; data: Array<JobReport> }
| { key: 'JobGetHistory'; data: Array<JobReport> }
| { key: 'GetLibraryStatistics'; data: Statistics };
export type CoreResponse = { key: "Success", data: null } | { key: "SysGetVolumes", data: Array<Volume> } | { key: "SysGetLocation", data: LocationResource } | { key: "SysGetLocations", data: Array<LocationResource> } | { key: "LibGetExplorerDir", data: DirectoryWithContents } | { key: "NodeGetState", data: NodeState } | { key: "LocCreate", data: LocationResource } | { key: "JobGetRunning", data: Array<JobReport> } | { key: "JobGetHistory", data: Array<JobReport> } | { key: "GetLibraryStatistics", data: Statistics };

View file

@ -1,6 +1,4 @@
import type { FilePath } from './FilePath';
import type { File } from "./File";
import type { FilePath } from "./FilePath";
export interface DirectoryWithContents {
directory: FilePath;
contents: Array<FilePath>;
}
export interface DirectoryWithContents { directory: FilePath, contents: Array<File>, }

View file

@ -1 +1,2 @@
export type EncryptionAlgorithm = 'None' | 'AES128' | 'AES192' | 'AES256';
export type EncryptionAlgorithm = "None" | "AES128" | "AES192" | "AES256";

View file

@ -1,24 +1,4 @@
import type { EncryptionAlgorithm } from './EncryptionAlgorithm';
import type { FileKind } from './FileKind';
import type { FilePath } from './FilePath';
import type { FileKind } from "./FileKind";
import type { FilePath } from "./FilePath";
export interface File {
id: number;
cas_id: string;
integrity_checksum: string | null;
size_in_bytes: string;
kind: FileKind;
hidden: boolean;
favorite: boolean;
important: boolean;
has_thumbnail: boolean;
has_thumbstrip: boolean;
has_video_preview: boolean;
encryption: EncryptionAlgorithm;
ipfs_id: string | null;
comment: string | null;
date_created: string;
date_modified: string;
date_indexed: string;
paths: Array<FilePath>;
}
export interface File { id: number, cas_id: string, integrity_checksum: string | null, size_in_bytes: string, kind: FileKind, hidden: boolean, favorite: boolean, important: boolean, has_thumbnail: boolean, has_thumbstrip: boolean, has_video_preview: boolean, ipfs_id: string | null, comment: string | null, date_created: string, date_modified: string, date_indexed: string, paths: Array<FilePath>, }

View file

@ -1,10 +1,2 @@
export type FileKind =
| 'Unknown'
| 'Directory'
| 'Package'
| 'Archive'
| 'Image'
| 'Video'
| 'Audio'
| 'Plaintext'
| 'Alias';
export type FileKind = "Unknown" | "Directory" | "Package" | "Archive" | "Image" | "Video" | "Audio" | "Plaintext" | "Alias";

View file

@ -1,16 +1,2 @@
export interface FilePath {
id: number;
is_dir: boolean;
location_id: number;
materialized_path: string;
name: string;
extension: string | null;
file_id: number | null;
parent_id: number | null;
temp_cas_id: string | null;
has_local_thumbnail: boolean;
date_created: string;
date_modified: string;
date_indexed: string;
permissions: string | null;
}
export interface FilePath { id: number, is_dir: boolean, location_id: number, materialized_path: string, name: string, extension: string | null, file_id: number | null, parent_id: number | null, has_local_thumbnail: boolean, date_created: string, date_modified: string, date_indexed: string, }

View file

@ -1,12 +1,3 @@
import type { JobStatus } from './JobStatus';
import type { JobStatus } from "./JobStatus";
export interface JobReport {
id: string;
date_created: string;
date_modified: string;
status: JobStatus;
task_count: number;
completed_task_count: number;
message: string;
seconds_elapsed: string;
}
export interface JobReport { id: string, name: string, date_created: string, date_modified: string, status: JobStatus, task_count: number, completed_task_count: number, message: string, seconds_elapsed: string, }

View file

@ -1 +1,2 @@
export type JobStatus = 'Queued' | 'Running' | 'Completed' | 'Canceled' | 'Failed';
export type JobStatus = "Queued" | "Running" | "Completed" | "Canceled" | "Failed";

View file

@ -0,0 +1,3 @@
import type { Platform } from "./Platform";
export interface LibraryNode { uuid: string, name: string, platform: Platform, tcp_address: string, last_seen: string, last_synchronized: string, }

View file

@ -1,6 +1,2 @@
export interface LibraryState {
library_uuid: string;
library_id: number;
library_path: string;
offline: boolean;
}
export interface LibraryState { library_uuid: string, library_id: number, library_path: string, offline: boolean, }

View file

@ -1,10 +1,2 @@
export interface LocationResource {
id: number;
name: string | null;
path: string | null;
total_capacity: number | null;
available_capacity: number | null;
is_removable: boolean | null;
is_online: boolean;
date_created: string;
}
export interface LocationResource { id: number, name: string | null, path: string | null, total_capacity: number | null, available_capacity: number | null, is_removable: boolean | null, is_online: boolean, date_created: string, }

View file

@ -0,0 +1,3 @@
import type { LibraryState } from "./LibraryState";
export interface NodeState { node_pub_id: string, node_id: number, node_name: string, data_path: string, tcp_port: number, libraries: Array<LibraryState>, current_library_uuid: string, }

View file

@ -1 +1,2 @@
export type Platform = 'Unknown' | 'Windows' | 'MacOS' | 'Linux' | 'IOS' | 'Android';
export type Platform = "Unknown" | "Windows" | "MacOS" | "Linux" | "IOS" | "Android";

View file

@ -1,9 +1,2 @@
export interface Statistics {
total_file_count: number;
total_bytes_used: string;
total_bytes_capacity: string;
total_bytes_free: string;
total_unique_bytes: string;
preview_media_bytes: string;
library_db_size: string;
}
export interface Statistics { total_file_count: number, total_bytes_used: string, total_bytes_capacity: string, total_bytes_free: string, total_unique_bytes: string, preview_media_bytes: string, library_db_size: string, }

View file

@ -1,10 +1,2 @@
export interface Volume {
name: string;
mount_point: string;
total_capacity: bigint;
available_capacity: bigint;
is_removable: boolean;
disk_type: string | null;
file_system: string | null;
is_root_filesystem: boolean;
}
export interface Volume { name: string, mount_point: string, total_capacity: bigint, available_capacity: bigint, is_removable: boolean, disk_type: string | null, file_system: string | null, is_root_filesystem: boolean, }

View file

@ -12,8 +12,10 @@ export * from './bindings/FileKind';
export * from './bindings/FilePath';
export * from './bindings/JobReport';
export * from './bindings/JobStatus';
export * from './bindings/LibraryNode';
export * from './bindings/LibraryState';
export * from './bindings/LocationResource';
export * from './bindings/NodeState';
export * from './bindings/Platform';
export * from './bindings/Statistics';
export * from './bindings/Volume';

View file

@ -70,15 +70,15 @@ pub async fn run_migrations(ctx: &CoreContext) -> Result<()> {
})
.collect::<Vec<_>>();
migration_subdirs.sort_by(|a, b| {
let a_name = a.path().file_name().unwrap().to_str().unwrap();
let b_name = b.path().file_name().unwrap().to_str().unwrap();
// migration_subdirs.sort_by(|a, b| {
// let a_name = a.path().file_name().unwrap().to_str().unwrap();
// let b_name = b.path().file_name().unwrap().to_str().unwrap();
let a_time = a_name[..14].parse::<i64>().unwrap();
let b_time = b_name[..14].parse::<i64>().unwrap();
// let a_time = a_name[..14].parse::<i64>().unwrap();
// let b_time = b_name[..14].parse::<i64>().unwrap();
a_time.cmp(&b_time)
});
// a_time.cmp(&b_time)
// });
for subdir in migration_subdirs {
println!("{:?}", subdir.path());

View file

@ -305,7 +305,7 @@ impl Node {
let ctx = self.get_context();
Ok(match query {
// return the client state from memory
ClientQuery::ClientGetState => CoreResponse::ClientGetState(self.state.clone()),
ClientQuery::NodeGetState => CoreResponse::NodeGetState(self.state.clone()),
// get system volumes without saving to library
ClientQuery::SysGetVolumes => {
CoreResponse::SysGetVolumes(sys::volumes::Volume::get_volumes()?)
@ -372,7 +372,7 @@ pub enum ClientCommand {
#[serde(tag = "key", content = "params")]
#[ts(export)]
pub enum ClientQuery {
ClientGetState,
NodeGetState,
SysGetVolumes,
LibGetTags,
JobGetRunning,
@ -413,7 +413,7 @@ pub enum CoreResponse {
SysGetLocation(sys::locations::LocationResource),
SysGetLocations(Vec<sys::locations::LocationResource>),
LibGetExplorerDir(file::DirectoryWithContents),
ClientGetState(NodeState),
NodeGetState(NodeState),
LocCreate(sys::locations::LocationResource),
JobGetRunning(Vec<JobReport>),
JobGetHistory(Vec<JobReport>),

View file

@ -41,6 +41,7 @@
"react-hotkeys-hook": "^3.4.4",
"react-json-view": "^1.21.3",
"react-loading-icons": "^1.0.8",
"react-loading-skeleton": "^3.1.0",
"react-portal": "^4.2.2",
"react-query": "^3.34.19",
"react-router": "6.3.0",

View file

@ -54,7 +54,6 @@ export interface AppProps {
isFocused?: boolean;
useMemoryRouter: boolean;
demoMode?: boolean;
demoData: string;
}
function AppLayout() {

View file

@ -61,7 +61,7 @@ export const FileList: React.FC<{ location_id: number; path: string; limit: numb
const tableContainer = useRef<null | HTMLDivElement>(null);
const VList = useRef<null | VirtuosoHandle>(null);
const { data: client } = useBridgeQuery('ClientGetState', undefined, {
const { data: client } = useBridgeQuery('NodeGetState', undefined, {
refetchOnWindowFocus: false
});

View file

@ -13,7 +13,7 @@ export default function FileThumb(props: {
className?: string;
}) {
const appPropsContext = useContext(AppPropsContext);
const { data: client } = useBridgeQuery('ClientGetState');
const { data: client } = useBridgeQuery('NodeGetState');
if (props.file.is_dir) {
return <Folder className="max-w-[170px]" />;

View file

@ -63,7 +63,7 @@ export const Sidebar: React.FC<SidebarProps> = (props) => {
const appPropsContext = useContext(AppPropsContext);
const { data: locations } = useBridgeQuery('SysGetLocations');
const { data: clientState } = useBridgeQuery('ClientGetState');
const { data: clientState } = useBridgeQuery('NodeGetState');
const { mutate: createLocation } = useBridgeCommand('LocCreate');
@ -98,9 +98,9 @@ export const Sidebar: React.FC<SidebarProps> = (props) => {
variant: 'gray'
}}
// buttonIcon={<Book weight="bold" className="w-4 h-4 mt-0.5 mr-1" />}
buttonText={clientState?.client_name || 'Loading...'}
buttonText={clientState?.node_name || 'Loading...'}
items={[
[{ name: clientState?.client_name || '', selected: true }, { name: 'Private Library' }],
[{ name: clientState?.node_name || '', selected: true }, { name: 'Private Library' }],
[
{ name: 'Library Settings', icon: CogIcon },
{ name: 'Add Library', icon: PlusIcon },

View file

@ -6,7 +6,7 @@ import CodeBlock from '../components/primitive/Codeblock';
export const DebugScreen: React.FC<{}> = (props) => {
const appPropsContext = useContext(AppPropsContext);
const { data: client } = useBridgeQuery('ClientGetState');
const { data: client } = useBridgeQuery('NodeGetState');
const { data: jobs } = useBridgeQuery('JobGetRunning');
const { data: jobHistory } = useBridgeQuery('JobGetHistory');
// const { mutate: purgeDB } = useBridgeCommand('PurgeDatabase', {

View file

@ -36,7 +36,7 @@ const StatItem: React.FC<StatItemProps> = (props) => {
end: amount,
delay: 0.1,
decimals: 1,
duration: appPropsContext?.demoMode ? 2 : 1,
duration: appPropsContext?.demoMode ? 1 : 0.5,
useEasing: true,
onEnd: () => {
setHasRun(true);
@ -60,7 +60,7 @@ const StatItem: React.FC<StatItemProps> = (props) => {
export const OverviewScreen: React.FC<{}> = (props) => {
const { data: libraryStatistics } = useBridgeQuery('GetLibraryStatistics');
const { data: clientState } = useBridgeQuery('ClientGetState');
const { data: clientState } = useBridgeQuery('NodeGetState');
const [stats, setStats] = useState<Statistics>(libraryStatistics || ({} as Statistics));

View file

@ -32,7 +32,7 @@ const Heading: React.FC<{ className?: string; children: string }> = ({ children,
export const SettingsScreen: React.FC<{}> = () => {
return (
<div className="flex flex-row w-full">
<div className="h-full border-r border-gray-100 w-60 dark:border-gray-550">
<div className="h-full border-r max-w-[200px] border-gray-100 w-60 dark:border-gray-550">
<div data-tauri-drag-region className="w-full h-7" />
<div className="p-5 pt-0">
<Heading className="mt-0">Client</Heading>

View file

@ -290,6 +290,7 @@ importers:
react-hotkeys-hook: ^3.4.4
react-json-view: ^1.21.3
react-loading-icons: ^1.0.8
react-loading-skeleton: ^3.1.0
react-portal: ^4.2.2
react-query: ^3.34.19
react-router: 6.3.0
@ -334,6 +335,7 @@ importers:
react-hotkeys-hook: 3.4.4_zpnidt7m3osuk7shl3s4oenomq
react-json-view: 1.21.3_ca3iilkt5tbo43h35hmeecyxuu
react-loading-icons: 1.0.8
react-loading-skeleton: 3.1.0_react@18.0.0
react-portal: 4.2.2_zpnidt7m3osuk7shl3s4oenomq
react-query: 3.34.19_zpnidt7m3osuk7shl3s4oenomq
react-router: 6.3.0_react@18.0.0
@ -6775,6 +6777,14 @@ packages:
resolution: {integrity: sha512-j0myUwDUPoo3qaPkbgnA7U2RNHqLLC+wXcpMWe+rtk3Iw+mGHltZ3QitPSHFKtsFKlpM9UlMmZGZ6sw6WVVW7w==}
dev: false
/react-loading-skeleton/3.1.0_react@18.0.0:
resolution: {integrity: sha512-j1U1CWWs68nBPOg7tkQqnlFcAMFF6oEK6MgqAo15f8A5p7mjH6xyKn2gHbkcimpwfO0VQXqxAswnSYVr8lWzjw==}
peerDependencies:
react: '>=16.8.0'
dependencies:
react: 18.0.0
dev: false
/react-portal/4.2.2_zpnidt7m3osuk7shl3s4oenomq:
resolution: {integrity: sha512-vS18idTmevQxyQpnde0Td6ZcUlv+pD8GTyR42n3CHUQq9OHi1C4jDE4ZWEbEsrbrLRhSECYiao58cvocwMtP7Q==}
peerDependencies: