merge duplicate prettier config and format repo with it

This commit is contained in:
Oscar Beaumont 2022-10-07 07:45:15 +08:00
parent fe4da9048a
commit aacdf33216
83 changed files with 1415 additions and 948 deletions

2
.prettierignore Normal file
View file

@ -0,0 +1,2 @@
/target
.build

View file

@ -7,7 +7,7 @@ module.exports = {
bracketSameLine: false,
semi: true,
quoteProps: 'consistent',
importOrder: ['^@sd/interface/(.*)$', '^@sd/client/(.*)$', '^@sd/ui/(.*)$', '^[./]'],
importOrder: ['^[./]', '^@sd/interface/(.*)$', '^@sd/client/(.*)$', '^@sd/ui/(.*)$'],
importOrderSeparation: true,
importOrderSortSpecifiers: true,
plugins: ['@trivago/prettier-plugin-sort-imports']

View file

@ -1,20 +0,0 @@
{
"pluginSearchDirs": [
"."
],
"useTabs": true,
"printWidth": 100,
"singleQuote": true,
"trailingComma": "none",
"bracketSameLine": false,
"semi": true,
"quoteProps": "consistent",
"importOrder": [
"^[./]",
"^@sd/ui/(.*)$",
"^@sd/client/(.*)$",
"^@sd/interface/(.*)$"
],
"importOrderSeparation": true,
"importOrderSortSpecifiers": true
}

View file

@ -109,4 +109,3 @@ This project is using what I'm calling the **"PRRTT"** stack (Prisma, Rust, Reac
- `ios`: A [Swift](https://developer.apple.com/swift/) Native binary (planned).
- `windows`: A [C#](https://docs.microsoft.com/en-us/dotnet/csharp/) Native binary (planned).
- `android`: A [Kotlin](https://kotlinlang.org/) Native binary (planned).

View file

@ -2,13 +2,13 @@ import { Button } from '@sd/ui';
import React from 'react';
import { PageContextBuiltIn } from 'vite-plugin-ssr';
import '@sd/ui/style';
import { Footer } from './components/Footer';
import NavBar from './components/NavBar';
import { PageContextProvider } from './renderer/usePageContext';
import './style.scss';
import '@sd/ui/style';
export default function App({
children,
pageContext

View file

@ -7,35 +7,35 @@ const ghostURL = import.meta.env.VITE_API_URL;
export const blogEnabled = !!(ghostURL && ghostKey);
export const api = blogEnabled
? new GhostContentAPI({
url: ghostURL,
key: ghostKey,
version: 'v5.0'
})
: null;
? new GhostContentAPI({
url: ghostURL,
key: ghostKey,
version: 'v5.0'
})
: null;
export async function getPosts() {
if (!api) {
return [];
}
const posts = await api.posts
.browse({
include: ['tags', 'authors']
})
.catch(() => []);
return posts;
if (!api) {
return [];
}
const posts = await api.posts
.browse({
include: ['tags', 'authors']
})
.catch(() => []);
return posts;
}
export async function getPost(slug: string) {
if (!api) {
return null;
}
return await api.posts
.read(
{ slug },
{
include: ['tags', 'authors']
}
)
.catch(() => null);
if (!api) {
return null;
}
return await api.posts
.read(
{ slug },
{
include: ['tags', 'authors']
}
)
.catch(() => null);
}

View file

@ -2,8 +2,6 @@ import clsx from 'clsx';
import { useEffect, useState } from 'react';
import { Helmet } from 'react-helmet';
import { ReactComponent as Info } from '@sd/interface/assets/svg/info.svg';
import AppEmbed, { AppEmbedPlaceholder } from '../components/AppEmbed';
import { Bubbles } from '../components/Bubbles';
// import { Bubbles } from '../components/Bubbles';
@ -12,6 +10,8 @@ import NewBanner from '../components/NewBanner';
import { usePageContext } from '../renderer/usePageContext';
import { getWindow } from '../utils';
import { ReactComponent as Info } from '@sd/interface/assets/svg/info.svg';
interface SectionProps {
orientation: 'left' | 'right';
heading?: string;

View file

@ -1,11 +1,11 @@
import { Helmet } from 'react-helmet';
import { ReactComponent as ArrowRight } from '@sd/interface/assets/svg/arrow-right.svg';
import Markdown from '../components/Markdown';
import { TeamMember, TeamMemberProps } from '../components/TeamMember';
import { resolveFilesGlob } from '../utils';
import { ReactComponent as ArrowRight } from '@sd/interface/assets/svg/arrow-right.svg';
const teamImages = resolveFilesGlob(import.meta.globEager('../assets/images/team/*'));
const investorImages = resolveFilesGlob(import.meta.globEager('../assets/images/investors/*'));

View file

@ -116,7 +116,7 @@ html {
&.bloom-one {
@apply left-0 -ml-[300px];
background: url('/bloom-one.png') no-repeat center center;
background-size: contain;
background-size: contain;
animation-delay: 300ms;
}
&.bloom-two {
@ -139,7 +139,6 @@ html {
background: url('/egg-bloom-two.png') no-repeat center center;
background-size: contain;
}
}
@keyframes bloomBurst {
@ -170,47 +169,48 @@ html {
}
.slot-block {
@apply bg-gray-550 py-3 px-4 border-l-4 border-gray-400 rounded mb-2
@apply bg-gray-550 py-3 px-4 border-l-4 border-gray-400 rounded mb-2;
}
.slot-block.note {
@apply border-yellow-400 bg-yellow-300/20
@apply border-yellow-400 bg-yellow-300/20;
}
.slot-block.info {
@apply border-green-400 bg-green-400/20
@apply border-green-400 bg-green-400/20;
}
.slot-block.warning {
@apply border-red-400 bg-red-400/20
@apply border-red-400 bg-red-400/20;
}
.slot-block-title {
@apply text-white font-bold text-sm m-0 uppercase;
}
.slot-block-content {
@apply my-1 mx-0 mb-0 text-white
@apply my-1 mx-0 mb-0 text-white;
}
.doc-sidebar-button:hover, .doc-sidebar-button.nav-active {
.doc-sidebar-button:hover,
.doc-sidebar-button.nav-active {
&.product {
color:#459EE8;
color: #459ee8;
div {
background-color: #459EE8;
background-color: #459ee8;
}
}
&.developers {
color:#48BB78;
color: #48bb78;
div {
background-color: #48BB78;
background-color: #48bb78;
}
}
&.company {
color:#bb9247;
color: #bb9247;
div {
background-color: #bb9247;
}
}
&.changelog {
color:#8A47BB;
color: #8a47bb;
div {
background-color: #8A47BB;
background-color: #8a47bb;
}
}
}
@ -222,7 +222,6 @@ html {
// #1D054B
// #9A3F8C
.custom-scroll {
-ms-overflow-style: none; /* for Internet Explorer, Edge */
scrollbar-width: none; /* for Firefox */
@ -238,7 +237,6 @@ html {
@apply bg-[#00000006] dark:bg-[#00000030] my-[10px] rounded-[6px];
}
&::-webkit-scrollbar-thumb {
@apply rounded-[6px] bg-gray-300 dark:bg-gray-550 ;
@apply rounded-[6px] bg-gray-300 dark:bg-gray-550;
}
}
}

View file

@ -1,122 +1,122 @@
{
"images": [
{
"idiom": "iphone",
"size": "20x20",
"scale": "2x",
"filename": "App-Icon-20x20@2x.png"
},
{
"idiom": "iphone",
"size": "20x20",
"scale": "3x",
"filename": "App-Icon-20x20@3x.png"
},
{
"idiom": "iphone",
"size": "29x29",
"scale": "1x",
"filename": "App-Icon-29x29@1x.png"
},
{
"idiom": "iphone",
"size": "29x29",
"scale": "2x",
"filename": "App-Icon-29x29@2x.png"
},
{
"idiom": "iphone",
"size": "29x29",
"scale": "3x",
"filename": "App-Icon-29x29@3x.png"
},
{
"idiom": "iphone",
"size": "40x40",
"scale": "2x",
"filename": "App-Icon-40x40@2x.png"
},
{
"idiom": "iphone",
"size": "40x40",
"scale": "3x",
"filename": "App-Icon-40x40@3x.png"
},
{
"idiom": "iphone",
"size": "60x60",
"scale": "2x",
"filename": "App-Icon-60x60@2x.png"
},
{
"idiom": "iphone",
"size": "60x60",
"scale": "3x",
"filename": "App-Icon-60x60@3x.png"
},
{
"idiom": "ipad",
"size": "20x20",
"scale": "1x",
"filename": "App-Icon-20x20@1x.png"
},
{
"idiom": "ipad",
"size": "20x20",
"scale": "2x",
"filename": "App-Icon-20x20@2x.png"
},
{
"idiom": "ipad",
"size": "29x29",
"scale": "1x",
"filename": "App-Icon-29x29@1x.png"
},
{
"idiom": "ipad",
"size": "29x29",
"scale": "2x",
"filename": "App-Icon-29x29@2x.png"
},
{
"idiom": "ipad",
"size": "40x40",
"scale": "1x",
"filename": "App-Icon-40x40@1x.png"
},
{
"idiom": "ipad",
"size": "40x40",
"scale": "2x",
"filename": "App-Icon-40x40@2x.png"
},
{
"idiom": "ipad",
"size": "76x76",
"scale": "1x",
"filename": "App-Icon-76x76@1x.png"
},
{
"idiom": "ipad",
"size": "76x76",
"scale": "2x",
"filename": "App-Icon-76x76@2x.png"
},
{
"idiom": "ipad",
"size": "83.5x83.5",
"scale": "2x",
"filename": "App-Icon-83.5x83.5@2x.png"
},
{
"idiom": "ios-marketing",
"size": "1024x1024",
"scale": "1x",
"filename": "ItunesArtwork@2x.png"
}
],
"info": {
"version": 1,
"author": "expo"
}
}
"images": [
{
"idiom": "iphone",
"size": "20x20",
"scale": "2x",
"filename": "App-Icon-20x20@2x.png"
},
{
"idiom": "iphone",
"size": "20x20",
"scale": "3x",
"filename": "App-Icon-20x20@3x.png"
},
{
"idiom": "iphone",
"size": "29x29",
"scale": "1x",
"filename": "App-Icon-29x29@1x.png"
},
{
"idiom": "iphone",
"size": "29x29",
"scale": "2x",
"filename": "App-Icon-29x29@2x.png"
},
{
"idiom": "iphone",
"size": "29x29",
"scale": "3x",
"filename": "App-Icon-29x29@3x.png"
},
{
"idiom": "iphone",
"size": "40x40",
"scale": "2x",
"filename": "App-Icon-40x40@2x.png"
},
{
"idiom": "iphone",
"size": "40x40",
"scale": "3x",
"filename": "App-Icon-40x40@3x.png"
},
{
"idiom": "iphone",
"size": "60x60",
"scale": "2x",
"filename": "App-Icon-60x60@2x.png"
},
{
"idiom": "iphone",
"size": "60x60",
"scale": "3x",
"filename": "App-Icon-60x60@3x.png"
},
{
"idiom": "ipad",
"size": "20x20",
"scale": "1x",
"filename": "App-Icon-20x20@1x.png"
},
{
"idiom": "ipad",
"size": "20x20",
"scale": "2x",
"filename": "App-Icon-20x20@2x.png"
},
{
"idiom": "ipad",
"size": "29x29",
"scale": "1x",
"filename": "App-Icon-29x29@1x.png"
},
{
"idiom": "ipad",
"size": "29x29",
"scale": "2x",
"filename": "App-Icon-29x29@2x.png"
},
{
"idiom": "ipad",
"size": "40x40",
"scale": "1x",
"filename": "App-Icon-40x40@1x.png"
},
{
"idiom": "ipad",
"size": "40x40",
"scale": "2x",
"filename": "App-Icon-40x40@2x.png"
},
{
"idiom": "ipad",
"size": "76x76",
"scale": "1x",
"filename": "App-Icon-76x76@1x.png"
},
{
"idiom": "ipad",
"size": "76x76",
"scale": "2x",
"filename": "App-Icon-76x76@2x.png"
},
{
"idiom": "ipad",
"size": "83.5x83.5",
"scale": "2x",
"filename": "App-Icon-83.5x83.5@2x.png"
},
{
"idiom": "ios-marketing",
"size": "1024x1024",
"scale": "1x",
"filename": "ItunesArtwork@2x.png"
}
],
"info": {
"version": 1,
"author": "expo"
}
}

View file

@ -1,6 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "expo"
}
"info": {
"version": 1,
"author": "expo"
}
}

View file

@ -1,21 +1,21 @@
{
"images": [
{
"idiom": "universal",
"filename": "image.png",
"scale": "1x"
},
{
"idiom": "universal",
"scale": "2x"
},
{
"idiom": "universal",
"scale": "3x"
}
],
"info": {
"version": 1,
"author": "expo"
}
}
"images": [
{
"idiom": "universal",
"filename": "image.png",
"scale": "1x"
},
{
"idiom": "universal",
"scale": "2x"
},
{
"idiom": "universal",
"scale": "3x"
}
],
"info": {
"version": 1,
"author": "expo"
}
}

View file

@ -1,21 +1,21 @@
{
"images": [
{
"idiom": "universal",
"filename": "image.png",
"scale": "1x"
},
{
"idiom": "universal",
"scale": "2x"
},
{
"idiom": "universal",
"scale": "3x"
}
],
"info": {
"version": 1,
"author": "expo"
}
}
"images": [
{
"idiom": "universal",
"filename": "image.png",
"scale": "1x"
},
{
"idiom": "universal",
"scale": "2x"
},
{
"idiom": "universal",
"scale": "3x"
}
],
"info": {
"version": 1,
"author": "expo"
}
}

View file

@ -2,111 +2,358 @@
// This file was generated by [rspc](https://github.com/oscartbeaumont/rspc). Do not edit this file manually.
export type Procedures = {
queries:
{ key: "files.readMetadata", input: LibraryArgs<number>, result: null } |
{ key: "getNode", input: never, result: NodeState } |
{ key: "jobs.getHistory", input: LibraryArgs<null>, result: Array<JobReport> } |
{ key: "jobs.getRunning", input: LibraryArgs<null>, result: Array<JobReport> } |
{ key: "library.getStatistics", input: LibraryArgs<null>, result: Statistics } |
{ key: "library.list", input: never, result: Array<LibraryConfigWrapped> } |
{ key: "locations.getById", input: LibraryArgs<number>, result: Location | null } |
{ key: "locations.getExplorerData", input: LibraryArgs<LocationExplorerArgs>, result: ExplorerData } |
{ key: "locations.indexer_rules.get", input: LibraryArgs<number>, result: IndexerRule } |
{ key: "locations.indexer_rules.list", input: LibraryArgs<null>, result: Array<IndexerRule> } |
{ key: "locations.list", input: LibraryArgs<null>, result: Array<{ id: number, pub_id: Array<number>, node_id: number, name: string | null, local_path: string | null, total_capacity: number | null, available_capacity: number | null, filesystem: string | null, disk_type: number | null, is_removable: boolean | null, is_online: boolean, is_archived: boolean, date_created: string, node: Node }> } |
{ key: "tags.get", input: LibraryArgs<number>, result: Tag | null } |
{ key: "tags.getExplorerData", input: LibraryArgs<number>, result: ExplorerData } |
{ key: "tags.getForObject", input: LibraryArgs<number>, result: Array<Tag> } |
{ key: "tags.list", input: LibraryArgs<null>, result: Array<Tag> } |
{ key: "version", input: never, result: string } |
{ key: "volumes.list", input: never, result: Array<Volume> },
mutations:
{ key: "files.delete", input: LibraryArgs<number>, result: null } |
{ key: "files.setFavorite", input: LibraryArgs<SetFavoriteArgs>, result: null } |
{ key: "files.setNote", input: LibraryArgs<SetNoteArgs>, result: null } |
{ key: "jobs.generateThumbsForLocation", input: LibraryArgs<GenerateThumbsForLocationArgs>, result: null } |
{ key: "jobs.identifyUniqueFiles", input: LibraryArgs<IdentifyUniqueFilesArgs>, result: null } |
{ key: "library.create", input: string, result: LibraryConfigWrapped } |
{ key: "library.delete", input: string, result: null } |
{ key: "library.edit", input: EditLibraryArgs, result: null } |
{ key: "locations.create", input: LibraryArgs<LocationCreateArgs>, result: null } |
{ key: "locations.delete", input: LibraryArgs<number>, result: null } |
{ key: "locations.fullRescan", input: LibraryArgs<number>, result: null } |
{ key: "locations.indexer_rules.create", input: LibraryArgs<IndexerRuleCreateArgs>, result: IndexerRule } |
{ key: "locations.indexer_rules.delete", input: LibraryArgs<number>, result: null } |
{ key: "locations.quickRescan", input: LibraryArgs<null>, result: null } |
{ key: "locations.update", input: LibraryArgs<LocationUpdateArgs>, result: null } |
{ key: "tags.assign", input: LibraryArgs<TagAssignArgs>, result: null } |
{ key: "tags.create", input: LibraryArgs<TagCreateArgs>, result: Tag } |
{ key: "tags.delete", input: LibraryArgs<number>, result: null } |
{ key: "tags.update", input: LibraryArgs<TagUpdateArgs>, result: null },
subscriptions:
{ key: "invalidateQuery", input: never, result: InvalidateOperationEvent } |
{ key: "jobs.newThumbnail", input: LibraryArgs<null>, result: string }
queries:
| { key: 'files.readMetadata'; input: LibraryArgs<number>; result: null }
| { key: 'getNode'; input: never; result: NodeState }
| { key: 'jobs.getHistory'; input: LibraryArgs<null>; result: Array<JobReport> }
| { key: 'jobs.getRunning'; input: LibraryArgs<null>; result: Array<JobReport> }
| { key: 'library.getStatistics'; input: LibraryArgs<null>; result: Statistics }
| { key: 'library.list'; input: never; result: Array<LibraryConfigWrapped> }
| { key: 'locations.getById'; input: LibraryArgs<number>; result: Location | null }
| {
key: 'locations.getExplorerData';
input: LibraryArgs<LocationExplorerArgs>;
result: ExplorerData;
}
| { key: 'locations.indexer_rules.get'; input: LibraryArgs<number>; result: IndexerRule }
| { key: 'locations.indexer_rules.list'; input: LibraryArgs<null>; result: Array<IndexerRule> }
| {
key: 'locations.list';
input: LibraryArgs<null>;
result: Array<{
id: number;
pub_id: Array<number>;
node_id: number;
name: string | null;
local_path: string | null;
total_capacity: number | null;
available_capacity: number | null;
filesystem: string | null;
disk_type: number | null;
is_removable: boolean | null;
is_online: boolean;
is_archived: boolean;
date_created: string;
node: Node;
}>;
}
| { key: 'tags.get'; input: LibraryArgs<number>; result: Tag | null }
| { key: 'tags.getExplorerData'; input: LibraryArgs<number>; result: ExplorerData }
| { key: 'tags.getForObject'; input: LibraryArgs<number>; result: Array<Tag> }
| { key: 'tags.list'; input: LibraryArgs<null>; result: Array<Tag> }
| { key: 'version'; input: never; result: string }
| { key: 'volumes.list'; input: never; result: Array<Volume> };
mutations:
| { key: 'files.delete'; input: LibraryArgs<number>; result: null }
| { key: 'files.setFavorite'; input: LibraryArgs<SetFavoriteArgs>; result: null }
| { key: 'files.setNote'; input: LibraryArgs<SetNoteArgs>; result: null }
| {
key: 'jobs.generateThumbsForLocation';
input: LibraryArgs<GenerateThumbsForLocationArgs>;
result: null;
}
| { key: 'jobs.identifyUniqueFiles'; input: LibraryArgs<IdentifyUniqueFilesArgs>; result: null }
| { key: 'library.create'; input: string; result: LibraryConfigWrapped }
| { key: 'library.delete'; input: string; result: null }
| { key: 'library.edit'; input: EditLibraryArgs; result: null }
| { key: 'locations.create'; input: LibraryArgs<LocationCreateArgs>; result: null }
| { key: 'locations.delete'; input: LibraryArgs<number>; result: null }
| { key: 'locations.fullRescan'; input: LibraryArgs<number>; result: null }
| {
key: 'locations.indexer_rules.create';
input: LibraryArgs<IndexerRuleCreateArgs>;
result: IndexerRule;
}
| { key: 'locations.indexer_rules.delete'; input: LibraryArgs<number>; result: null }
| { key: 'locations.quickRescan'; input: LibraryArgs<null>; result: null }
| { key: 'locations.update'; input: LibraryArgs<LocationUpdateArgs>; result: null }
| { key: 'tags.assign'; input: LibraryArgs<TagAssignArgs>; result: null }
| { key: 'tags.create'; input: LibraryArgs<TagCreateArgs>; result: Tag }
| { key: 'tags.delete'; input: LibraryArgs<number>; result: null }
| { key: 'tags.update'; input: LibraryArgs<TagUpdateArgs>; result: null };
subscriptions:
| { key: 'invalidateQuery'; input: never; result: InvalidateOperationEvent }
| { key: 'jobs.newThumbnail'; input: LibraryArgs<null>; result: string };
};
export interface ConfigMetadata { version: string | null }
export interface ConfigMetadata {
version: string | null;
}
export interface EditLibraryArgs { id: string, name: string | null, description: string | null }
export interface EditLibraryArgs {
id: string;
name: string | null;
description: string | null;
}
export type ExplorerContext = { type: "Location" } & Location | { type: "Tag" } & Tag
export type ExplorerContext = ({ type: 'Location' } & Location) | ({ type: 'Tag' } & Tag);
export interface ExplorerData { context: ExplorerContext, items: Array<ExplorerItem> }
export interface ExplorerData {
context: ExplorerContext;
items: Array<ExplorerItem>;
}
export type ExplorerItem = { type: "Path" } & { id: number, is_dir: boolean, location_id: number, materialized_path: string, name: string, extension: string | null, object_id: number | null, parent_id: number | null, key_id: number | null, date_created: string, date_modified: string, date_indexed: string, object: Object | null } | { type: "Object" } & { id: number, cas_id: string, integrity_checksum: string | null, name: string | null, extension: string | null, kind: number, size_in_bytes: string, key_id: number | null, hidden: boolean, favorite: boolean, important: boolean, has_thumbnail: boolean, has_thumbstrip: boolean, has_video_preview: boolean, ipfs_id: string | null, note: string | null, date_created: string, date_modified: string, date_indexed: string, file_paths: Array<FilePath> }
export type ExplorerItem =
| ({ type: 'Path' } & {
id: number;
is_dir: boolean;
location_id: number;
materialized_path: string;
name: string;
extension: string | null;
object_id: number | null;
parent_id: number | null;
key_id: number | null;
date_created: string;
date_modified: string;
date_indexed: string;
object: Object | null;
})
| ({ type: 'Object' } & {
id: number;
cas_id: string;
integrity_checksum: string | null;
name: string | null;
extension: string | null;
kind: number;
size_in_bytes: string;
key_id: number | null;
hidden: boolean;
favorite: boolean;
important: boolean;
has_thumbnail: boolean;
has_thumbstrip: boolean;
has_video_preview: boolean;
ipfs_id: string | null;
note: string | null;
date_created: string;
date_modified: string;
date_indexed: string;
file_paths: Array<FilePath>;
});
export interface FilePath { id: number, is_dir: boolean, location_id: number, materialized_path: string, name: string, extension: string | null, object_id: number | null, parent_id: number | null, key_id: number | null, date_created: string, date_modified: string, date_indexed: string }
export interface FilePath {
id: number;
is_dir: boolean;
location_id: number;
materialized_path: string;
name: string;
extension: string | null;
object_id: number | null;
parent_id: number | null;
key_id: number | null;
date_created: string;
date_modified: string;
date_indexed: string;
}
export interface GenerateThumbsForLocationArgs { id: number, path: string }
export interface GenerateThumbsForLocationArgs {
id: number;
path: string;
}
export interface IdentifyUniqueFilesArgs { id: number, path: string }
export interface IdentifyUniqueFilesArgs {
id: number;
path: string;
}
export interface IndexerRule { id: number, kind: number, name: string, parameters: Array<number>, date_created: string, date_modified: string }
export interface IndexerRule {
id: number;
kind: number;
name: string;
parameters: Array<number>;
date_created: string;
date_modified: string;
}
export interface IndexerRuleCreateArgs { kind: RuleKind, name: string, parameters: Array<number> }
export interface IndexerRuleCreateArgs {
kind: RuleKind;
name: string;
parameters: Array<number>;
}
export interface InvalidateOperationEvent { key: string, arg: any }
export interface InvalidateOperationEvent {
key: string;
arg: any;
}
export interface JobReport { id: string, name: string, data: Array<number> | null, metadata: any | null, date_created: string, date_modified: string, status: JobStatus, task_count: number, completed_task_count: number, message: string, seconds_elapsed: number }
export interface JobReport {
id: string;
name: string;
data: Array<number> | null;
metadata: any | null;
date_created: string;
date_modified: string;
status: JobStatus;
task_count: number;
completed_task_count: number;
message: string;
seconds_elapsed: number;
}
export type JobStatus = "Queued" | "Running" | "Completed" | "Canceled" | "Failed" | "Paused"
export type JobStatus = 'Queued' | 'Running' | 'Completed' | 'Canceled' | 'Failed' | 'Paused';
export interface LibraryArgs<T> { library_id: string, arg: T }
export interface LibraryArgs<T> {
library_id: string;
arg: T;
}
export interface LibraryConfig { version: string | null, name: string, description: string }
export interface LibraryConfig {
version: string | null;
name: string;
description: string;
}
export interface LibraryConfigWrapped { uuid: string, config: LibraryConfig }
export interface LibraryConfigWrapped {
uuid: string;
config: LibraryConfig;
}
export interface Location { id: number, pub_id: Array<number>, node_id: number, name: string | null, local_path: string | null, total_capacity: number | null, available_capacity: number | null, filesystem: string | null, disk_type: number | null, is_removable: boolean | null, is_online: boolean, is_archived: boolean, date_created: string }
export interface Location {
id: number;
pub_id: Array<number>;
node_id: number;
name: string | null;
local_path: string | null;
total_capacity: number | null;
available_capacity: number | null;
filesystem: string | null;
disk_type: number | null;
is_removable: boolean | null;
is_online: boolean;
is_archived: boolean;
date_created: string;
}
export interface LocationCreateArgs { path: string, indexer_rules_ids: Array<number> }
export interface LocationCreateArgs {
path: string;
indexer_rules_ids: Array<number>;
}
export interface LocationExplorerArgs { location_id: number, path: string, limit: number, cursor: string | null }
export interface LocationExplorerArgs {
location_id: number;
path: string;
limit: number;
cursor: string | null;
}
export interface LocationUpdateArgs { id: number, name: string | null, indexer_rules_ids: Array<number> }
export interface LocationUpdateArgs {
id: number;
name: string | null;
indexer_rules_ids: Array<number>;
}
export interface Node { id: number, pub_id: Array<number>, name: string, platform: number, version: string | null, last_seen: string, timezone: string | null, date_created: string }
export interface Node {
id: number;
pub_id: Array<number>;
name: string;
platform: number;
version: string | null;
last_seen: string;
timezone: string | null;
date_created: string;
}
export interface NodeConfig { version: string | null, id: string, name: string, p2p_port: number | null }
export interface NodeConfig {
version: string | null;
id: string;
name: string;
p2p_port: number | null;
}
export interface NodeState { version: string | null, id: string, name: string, p2p_port: number | null, data_path: string }
export interface NodeState {
version: string | null;
id: string;
name: string;
p2p_port: number | null;
data_path: string;
}
export interface Object { id: number, cas_id: string, integrity_checksum: string | null, name: string | null, extension: string | null, kind: number, size_in_bytes: string, key_id: number | null, hidden: boolean, favorite: boolean, important: boolean, has_thumbnail: boolean, has_thumbstrip: boolean, has_video_preview: boolean, ipfs_id: string | null, note: string | null, date_created: string, date_modified: string, date_indexed: string }
export interface Object {
id: number;
cas_id: string;
integrity_checksum: string | null;
name: string | null;
extension: string | null;
kind: number;
size_in_bytes: string;
key_id: number | null;
hidden: boolean;
favorite: boolean;
important: boolean;
has_thumbnail: boolean;
has_thumbstrip: boolean;
has_video_preview: boolean;
ipfs_id: string | null;
note: string | null;
date_created: string;
date_modified: string;
date_indexed: string;
}
export type RuleKind = "AcceptFilesByGlob" | "RejectFilesByGlob" | "AcceptIfChildrenDirectoriesArePresent" | "RejectIfChildrenDirectoriesArePresent"
export type RuleKind =
| 'AcceptFilesByGlob'
| 'RejectFilesByGlob'
| 'AcceptIfChildrenDirectoriesArePresent'
| 'RejectIfChildrenDirectoriesArePresent';
export interface SetFavoriteArgs { id: number, favorite: boolean }
export interface SetFavoriteArgs {
id: number;
favorite: boolean;
}
export interface SetNoteArgs { id: number, note: string | null }
export interface SetNoteArgs {
id: number;
note: string | null;
}
export interface Statistics { id: number, date_captured: string, total_object_count: number, library_db_size: string, total_bytes_used: string, total_bytes_capacity: string, total_unique_bytes: string, total_bytes_free: string, preview_media_bytes: string }
export interface Statistics {
id: number;
date_captured: string;
total_object_count: number;
library_db_size: string;
total_bytes_used: string;
total_bytes_capacity: string;
total_unique_bytes: string;
total_bytes_free: string;
preview_media_bytes: string;
}
export interface Tag { id: number, pub_id: Array<number>, name: string | null, color: string | null, total_objects: number | null, redundancy_goal: number | null, date_created: string, date_modified: string }
export interface Tag {
id: number;
pub_id: Array<number>;
name: string | null;
color: string | null;
total_objects: number | null;
redundancy_goal: number | null;
date_created: string;
date_modified: string;
}
export interface TagAssignArgs { object_id: number, tag_id: number, unassign: boolean }
export interface TagAssignArgs {
object_id: number;
tag_id: number;
unassign: boolean;
}
export interface TagCreateArgs { name: string, color: string }
export interface TagCreateArgs {
name: string;
color: string;
}
export interface TagUpdateArgs { id: number, name: string | null, color: string | null }
export interface TagUpdateArgs {
id: number;
name: string | null;
color: string | null;
}
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

@ -1,15 +1,13 @@
<!DOCTYPE html>
<html class="dark">
<head>
<meta charset="utf-8" />
<title>Spacedrive</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<head>
<meta charset="utf-8" />
<title>Spacedrive</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
</head>
<body>
<div id="root"></div>
<script type="module" src="./index.tsx"></script>
</body>
<body>
<div id="root"></div>
<script type="module" src="./index.tsx"></script>
</body>
</html>

View file

@ -1,8 +1,10 @@
import App from './App';
import '@sd/ui/style';
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import '@sd/ui/style';
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
<React.StrictMode>

View file

@ -1,7 +1,5 @@
{
"extends": "../../packages/config/interface.tsconfig.json",
"compilerOptions": {},
"include": [
"src"
]
"extends": "../../packages/config/interface.tsconfig.json",
"compilerOptions": {},
"include": ["src"]
}

View file

@ -1,6 +1,6 @@
# FFMPEG Thumbnailer RS
Rust implementation of a thumbnail generation for video files using ffmpeg.
Rust implementation of a thumbnail generation for video files using ffmpeg.
Based on https://github.com/dirkvdb/ffmpegthumbnailer
For now only implements the minimum API for Spacedrive needs. PRs are welcome
@ -32,8 +32,8 @@ async fn main() -> Result<(), ThumbnailerError> {
.with_film_strip(false)
.quality(80.0)?
.build();
thumbnailer.process("input.mp4", "output.webp").await
}
```
```

View file

@ -6,4 +6,4 @@ This is the P2P library which powers Spacedrive's P2P functionality.
```bash
RUST_LOG="p2p=debug" cargo run -p server
```
```

View file

@ -4,7 +4,7 @@ This document outlines the peer to peer protocol used by the Spacedrive desktop
## Concepts
- **Peer** - TODO
- **Peer** - TODO
### P2PManager
@ -34,7 +34,7 @@ To discovery other machines running Spacedrive over your local network, we make
Spacedrive advertise a SRV record that looks like:
_{peer_id}_spacedrive_._udp_.local. 86400 IN SRV 10 5 5223 server.example.com.
_{peer_id}\_spacedrive_._udp_.local. 86400 IN SRV 10 5 5223 server.example.com.
This system will continue to passively discover clients while Spacedrive is running.
@ -58,24 +58,11 @@ TODO
Message::QueryClientAnnouncement(vec![peer_id, peer_id2]);
```
## General Overview
This system is designed on top of the following main technologies:
- [QUIC]() - A tcp-like protocol built on top of UDP. QUIC also supports [TLS 1.3]() for encryption and pro
- [QUIC]() - A tcp-like protocol built on top of UDP. QUIC also supports [TLS 1.3]() for encryption and pro
## Pairing
@ -83,5 +70,5 @@ TODO
# External Resources
- TODO: Magic Wormhole talk
- TODO: Syncthing spec
- TODO: Magic Wormhole talk
- TODO: Syncthing spec

View file

@ -9,4 +9,4 @@ TODO: Write some docs
```bash
cargo run -p tunnel --bin generate-env
cargo run -p tunnel
```
```

View file

@ -1,4 +1,3 @@
# crdt-rs
Just @brendonovich experimenting with CRDT stuff.

View file

@ -1,5 +1,3 @@
```rust
pub fn update_with_timestamp(&self, timestamp: &Timestamp) -> Result<(), String> {
let mut now = (self.clock)();
@ -31,49 +29,45 @@ pub fn update_with_timestamp(&self, timestamp: &Timestamp) -> Result<(), String>
```
```javascript
Timestamp.recv = function(msg) {
if (!clock) {
return null;
}
Timestamp.recv = function (msg) {
if (!clock) {
return null;
}
var now = Date.now();
var now = Date.now();
var msg_time = msg.millis();
var msg_time = msg.counter();
var msg_time = msg.millis();
var msg_time = msg.counter();
if (msg_time - now > config.maxDrift) {
throw new Timestamp.ClockDriftError();
}
if (msg_time - now > config.maxDrift) {
throw new Timestamp.ClockDriftError();
}
var last_time = clock.timestamp.millis();
var last_time = clock.timestamp.counter();
var last_time = clock.timestamp.millis();
var last_time = clock.timestamp.counter();
var max_time = Math.max(Math.max(last_time, now), msg_time);
var max_time = Math.max(Math.max(last_time, now), msg_time);
var last_time =
max_time === last_time && lNew === msg_time
? Math.max(last_time, msg_time) + 1
: max_time === last_time
? last_time + 1
: max_time === msg_time
? msg_time + 1
: 0;
var last_time =
max_time === last_time && lNew === msg_time
? Math.max(last_time, msg_time) + 1
: max_time === last_time
? last_time + 1
: max_time === msg_time
? msg_time + 1
: 0;
// 3.
if (max_time - phys > config.maxDrift) {
throw new Timestamp.ClockDriftError();
}
if (last_time > MAX_COUNTER) {
throw new Timestamp.OverflowError();
}
// 3.
if (max_time - phys > config.maxDrift) {
throw new Timestamp.ClockDriftError();
}
if (last_time > MAX_COUNTER) {
throw new Timestamp.OverflowError();
}
clock.timestamp.setMillis(max_time);
clock.timestamp.setCounter(last_time);
clock.timestamp.setMillis(max_time);
clock.timestamp.setCounter(last_time);
return new Timestamp(
clock.timestamp.millis(),
clock.timestamp.counter(),
clock.timestamp.node()
);
return new Timestamp(clock.timestamp.millis(), clock.timestamp.counter(), clock.timestamp.node());
};
```

View file

@ -1,3 +1,3 @@
{
"recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
"recommendations": ["tauri-apps.tauri-vscode", "rust-lang.rust-analyzer"]
}

View file

@ -1,17 +1,17 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="icon" type="image/svg+xml" href="/src/assets/logo.svg" />
<title>Tauri + Solid + Typescript App</title>
</head>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="icon" type="image/svg+xml" href="/src/assets/logo.svg" />
<title>Tauri + Solid + Typescript App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="/src/index.tsx" type="module"></script>
</body>
<script src="/src/index.tsx" type="module"></script>
</body>
</html>

View file

@ -1,32 +1,32 @@
{
"name": "@sd/sync-example",
"version": "0.0.0",
"description": "",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"tauri": "tauri"
},
"license": "MIT",
"devDependencies": {
"@tauri-apps/cli": "^1.1.1",
"@types/babel__core": "^7.1.19",
"@types/node": "^18.8.2",
"autoprefixer": "^10.4.12",
"postcss": "^8.4.17",
"tailwindcss": "^3.1.8",
"typescript": "^4.8.4",
"vite": "^3.1.4",
"vite-plugin-solid": "^2.3.9"
},
"dependencies": {
"@rspc/client": "~0.1.2",
"@rspc/solid": "~0.1.2",
"@rspc/tauri": "~0.1.2",
"@tanstack/solid-query": "4.10.1",
"clsx": "^1.2.1",
"solid-js": "^1.5.7"
}
"name": "@sd/sync-example",
"version": "0.0.0",
"description": "",
"scripts": {
"start": "vite",
"dev": "vite",
"build": "vite build",
"serve": "vite preview",
"tauri": "tauri"
},
"license": "MIT",
"devDependencies": {
"@tauri-apps/cli": "^1.1.1",
"@types/babel__core": "^7.1.19",
"@types/node": "^18.8.2",
"autoprefixer": "^10.4.12",
"postcss": "^8.4.17",
"tailwindcss": "^3.1.8",
"typescript": "^4.8.4",
"vite": "^3.1.4",
"vite-plugin-solid": "^2.3.9"
},
"dependencies": {
"@rspc/client": "~0.1.2",
"@rspc/solid": "~0.1.2",
"@rspc/tauri": "~0.1.2",
"@tanstack/solid-query": "4.10.1",
"clsx": "^1.2.1",
"solid-js": "^1.5.7"
}
}

View file

@ -1,66 +1,66 @@
{
"build": {
"beforeDevCommand": "pnpm dev",
"beforeBuildCommand": "pnpm build",
"devPath": "http://localhost:1420",
"distDir": "../dist",
"withGlobalTauri": false
},
"package": {
"productName": "example",
"version": "0.0.0"
},
"tauri": {
"allowlist": {
"all": true
},
"bundle": {
"active": true,
"category": "DeveloperTool",
"copyright": "",
"deb": {
"depends": []
},
"externalBin": [],
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
],
"identifier": "com.tauri.dev",
"longDescription": "",
"macOS": {
"entitlements": null,
"exceptionDomain": "",
"frameworks": [],
"providerShortName": null,
"signingIdentity": null
},
"resources": [],
"shortDescription": "",
"targets": "all",
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": ""
}
},
"security": {
"csp": null
},
"updater": {
"active": false
},
"windows": [
{
"fullscreen": false,
"height": 600,
"resizable": true,
"title": "example",
"width": 800
}
]
}
"build": {
"beforeDevCommand": "pnpm dev",
"beforeBuildCommand": "pnpm build",
"devPath": "http://localhost:1420",
"distDir": "../dist",
"withGlobalTauri": false
},
"package": {
"productName": "example",
"version": "0.0.0"
},
"tauri": {
"allowlist": {
"all": true
},
"bundle": {
"active": true,
"category": "DeveloperTool",
"copyright": "",
"deb": {
"depends": []
},
"externalBin": [],
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
],
"identifier": "com.tauri.dev",
"longDescription": "",
"macOS": {
"entitlements": null,
"exceptionDomain": "",
"frameworks": [],
"providerShortName": null,
"signingIdentity": null
},
"resources": [],
"shortDescription": "",
"targets": "all",
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": ""
}
},
"security": {
"csp": null
},
"updater": {
"active": false
},
"windows": [
{
"fullscreen": false,
"height": 600,
"resizable": true,
"title": "example",
"width": 800
}
]
}
}

View file

@ -1,75 +1,69 @@
import clsx from "clsx";
import { createSignal, For, JSX, Suspense } from "solid-js";
import { queryClient, rspc } from "./rspc";
import clsx from 'clsx';
import { For, JSX, Suspense, createSignal } from 'solid-js';
import { queryClient, rspc } from './rspc';
export function App() {
const dbs = rspc.createQuery(() => ["dbs"]);
const dbs = rspc.createQuery(() => ['dbs']);
const createDb = rspc.createMutation("createDatabase", {
onSuccess: () => {
queryClient.invalidateQueries();
},
});
const removeDbs = rspc.createMutation("removeDatabases", {
onSuccess: () => queryClient.invalidateQueries(),
});
const createDb = rspc.createMutation('createDatabase', {
onSuccess: () => {
queryClient.invalidateQueries();
}
});
const removeDbs = rspc.createMutation('removeDatabases', {
onSuccess: () => queryClient.invalidateQueries()
});
return (
<div class="p-4 space-y-4">
<div class="space-x-4">
<Button onClick={() => createDb.mutate(undefined)}>Add Database</Button>
<Button onClick={() => removeDbs.mutate(undefined)}>
Remove Databases
</Button>
</div>
<ul class="gap-2 flex flex-row flex-wrap">
<For each={dbs.data}>
{(id) => (
<Suspense fallback={null}>
<DatabaseView id={id} />
</Suspense>
)}
</For>
</ul>
</div>
);
return (
<div class="p-4 space-y-4">
<div class="space-x-4">
<Button onClick={() => createDb.mutate(undefined)}>Add Database</Button>
<Button onClick={() => removeDbs.mutate(undefined)}>Remove Databases</Button>
</div>
<ul class="gap-2 flex flex-row flex-wrap">
<For each={dbs.data}>
{(id) => (
<Suspense fallback={null}>
<DatabaseView id={id} />
</Suspense>
)}
</For>
</ul>
</div>
);
}
interface DatabaseViewProps {
id: string;
id: string;
}
const TABS = ["Tags", "Files", "File Paths", "Messages"];
const TABS = ['Tags', 'Files', 'File Paths', 'Messages'];
function DatabaseView(props: DatabaseViewProps) {
const [currentTab, setCurrentTab] = createSignal<typeof TABS[number]>("Tags");
const [currentTab, setCurrentTab] = createSignal<typeof TABS[number]>('Tags');
return (
<div class="bg-indigo-300 rounded-md min-w-[40rem] flex-1 overflow-hidden">
<h1 class="p-2 text-xl font-medium">{props.id}</h1>
<div>
<nav class="space-x-2">
<For each={TABS}>
{(tab) => (
<button
class={clsx(
"px-2 py-1",
tab === currentTab() && "bg-indigo-400"
)}
onClick={() => setCurrentTab(tab)}
>
{tab}
</button>
)}
</For>
</nav>
<div></div>
</div>
</div>
);
return (
<div class="bg-indigo-300 rounded-md min-w-[40rem] flex-1 overflow-hidden">
<h1 class="p-2 text-xl font-medium">{props.id}</h1>
<div>
<nav class="space-x-2">
<For each={TABS}>
{(tab) => (
<button
class={clsx('px-2 py-1', tab === currentTab() && 'bg-indigo-400')}
onClick={() => setCurrentTab(tab)}
>
{tab}
</button>
)}
</For>
</nav>
<div></div>
</div>
</div>
);
}
function Button(props: JSX.ButtonHTMLAttributes<HTMLButtonElement>) {
return (
<button {...props} class="bg-blue-500 text-white px-2 py-1 rounded-md" />
);
return <button {...props} class="bg-blue-500 text-white px-2 py-1 rounded-md" />;
}

View file

@ -1,15 +1,22 @@
// This file was generated by [rspc](https://github.com/oscartbeaumont/rspc). Do not edit this file manually.
export type Procedures = {
queries:
{ key: "db.tags", input: string, result: Record<string, Tag> } |
{ key: "dbs", input: never, result: Array<string> },
mutations:
{ key: "createDatabase", input: never, result: string } |
{ key: "removeDatabases", input: never, result: null },
subscriptions: never
queries:
| { key: 'db.tags'; input: string; result: Record<string, Tag> }
| { key: 'dbs'; input: never; result: Array<string> };
mutations:
| { key: 'createDatabase'; input: never; result: string }
| { key: 'removeDatabases'; input: never; result: null };
subscriptions: never;
};
export interface Color { red: number, green: number, blue: number }
export interface Color {
red: number;
green: number;
blue: number;
}
export interface Tag { color: Color, name: string }
export interface Tag {
color: Color;
name: string;
}

View file

@ -1,17 +1,17 @@
/* @refresh reload */
import { render, Suspense } from "solid-js/web";
import { Suspense, render } from 'solid-js/web';
import "./index.css";
import { App } from "./App";
import { queryClient, rspc, rspcClient } from "./rspc";
import { App } from './App';
import './index.css';
import { queryClient, rspc, rspcClient } from './rspc';
render(
() => (
<rspc.Provider client={rspcClient} queryClient={queryClient}>
<Suspense fallback={null}>
<App />
</Suspense>
</rspc.Provider>
),
document.getElementById("root") as HTMLElement
() => (
<rspc.Provider client={rspcClient} queryClient={queryClient}>
<Suspense fallback={null}>
<App />
</Suspense>
</rspc.Provider>
),
document.getElementById('root') as HTMLElement
);

View file

@ -1,22 +1,24 @@
import { QueryClient } from "@tanstack/solid-query";
import { createSolidQueryHooks } from "@rspc/solid";
import { createClient } from "@rspc/client";
import { TauriTransport } from "@rspc/tauri";
import { createClient } from '@rspc/client';
import { createSolidQueryHooks } from '@rspc/solid';
import { TauriTransport } from '@rspc/tauri';
import { QueryClient } from '@tanstack/solid-query';
import type { Procedures } from "./bindings"; // These were the bindings exported from your Rust code!
import type { Procedures } from './bindings';
// These were the bindings exported from your Rust code!
// You must provide the generated types as a generic and create a transport (in this example we are using HTTP Fetch) so that the client knows how to communicate with your API.
export const rspcClient = createClient<Procedures>({
// Refer to the integration your using for the correct transport.
transport: new TauriTransport(),
// Refer to the integration your using for the correct transport.
transport: new TauriTransport()
});
export const queryClient = new QueryClient({
defaultOptions: {
queries: {
suspense: true,
},
},
defaultOptions: {
queries: {
suspense: true
}
}
});
export const rspc = createSolidQueryHooks<Procedures>();

View file

@ -1,15 +1,15 @@
{
"compilerOptions": {
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"types": ["vite/client"],
"noEmit": true,
"isolatedModules": true
}
"compilerOptions": {
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "Node",
"allowSyntheticDefaultImports": true,
"esModuleInterop": true,
"jsx": "preserve",
"jsxImportSource": "solid-js",
"types": ["vite/client"],
"noEmit": true,
"isolatedModules": true
}
}

View file

@ -1,25 +1,25 @@
import { defineConfig } from "vite";
import solidPlugin from "vite-plugin-solid";
import { defineConfig } from 'vite';
import solidPlugin from 'vite-plugin-solid';
export default defineConfig({
plugins: [solidPlugin()],
// Vite optons tailored for Tauri development and only applied in `tauri dev` or `tauri build`
// prevent vite from obscuring rust errors
clearScreen: false,
// tauri expects a fixed port, fail if that port is not available
server: {
port: 1420,
strictPort: true,
},
// to make use of `TAURI_DEBUG` and other env variables
// https://tauri.studio/v1/api/config#buildconfig.beforedevcommand
envPrefix: ["VITE_", "TAURI_"],
build: {
// Tauri supports es2021
target: ["es2021", "chrome100", "safari13"],
// don't minify for debug builds
minify: !process.env.TAURI_DEBUG ? "esbuild" : false,
// produce sourcemaps for debug builds
sourcemap: !!process.env.TAURI_DEBUG,
},
plugins: [solidPlugin()],
// Vite optons tailored for Tauri development and only applied in `tauri dev` or `tauri build`
// prevent vite from obscuring rust errors
clearScreen: false,
// tauri expects a fixed port, fail if that port is not available
server: {
port: 1420,
strictPort: true
},
// to make use of `TAURI_DEBUG` and other env variables
// https://tauri.studio/v1/api/config#buildconfig.beforedevcommand
envPrefix: ['VITE_', 'TAURI_'],
build: {
// Tauri supports es2021
target: ['es2021', 'chrome100', 'safari13'],
// don't minify for debug builds
minify: !process.env.TAURI_DEBUG ? 'esbuild' : false,
// produce sourcemaps for debug builds
sourcemap: !!process.env.TAURI_DEBUG
}
});

View file

@ -4,13 +4,13 @@
This release has not happened yet, stay tuned...
:::
After __ months of development we are extremely excited to be releasing the first version of Spacedrive as an early public beta.
After \_\_ months of development we are extremely excited to be releasing the first version of Spacedrive as an early public beta.
This is an MVP, and by no means feature complete. Please test out the features listed below and give us feedback via Discord, email or GitHub Issues :D
This release is missing database synchronization between nodes (your devices), for now this renders connecting nodes useless, other than to transfer individual files. But don't worry, its coming very soon!
*Features:*
_Features:_
- Support for Windows, Linux and macOS, iOS and Android.
@ -21,20 +21,20 @@ This release is missing database synchronization between nodes (your devices), f
- Connect multiple [Nodes](../architecture/nodes.md) to a Library via LAN.
- Add [Locations](../architecture/locations.md) to import files into Spacedrive.
- Indexer watch for changes and performs light re-scans.
- Identifier generates checksum and categorizes files into [Objects]()
- Define rules for indexer to ignore certain files or folders.
*Eventually Clouds will be supported and added as Cloud Locations*
_Eventually Clouds will be supported and added as Cloud Locations_
- Browse Locations via the [Explorer](../architecture/explorer.md) and view previews and metadata.
- Viewer options: row/grid item size, gap adjustment, show/hide info.
- Context menu: rename, copy, duplicate, delete, favorite and add tags.
- Multi-select with dedicated context menu options.
- Open with default OS app, in-app viewer (images/text only) or Apple Quicklook
- Automatically identify unique files to discover duplicates, shown in the inspector.
- Generate [Preview Media](../architecture/preview-media.md) for image, video and text.
@ -45,7 +45,7 @@ This release is missing database synchronization between nodes (your devices), f
- Automated Spaces can include files that match criteria.
*Eventually Spaces will be sharable, publically or privately*
_Eventually Spaces will be sharable, publically or privately_
- Create photo [Albums](../architecture/albums.md) and add images.
@ -67,4 +67,4 @@ This release is missing database synchronization between nodes (your devices), f
- Update installer.
- Optional crash reporting.
- Optional crash reporting.

View file

@ -74,4 +74,4 @@ limit any of our or your liabilities in any way that is not permitted under appl
exclude any of our or your liabilities that may not be excluded under applicable law.
The limitations and prohibitions of liability set in this Section and elsewhere in this disclaimer: (a) are subject to the preceding paragraph; and (b) govern all liabilities arising under the disclaimer, including liabilities arising in contract, in tort, and for breach of statutory duty.
As long as the website and the information and services on the website are provided free of charge, we will not be liable for any loss or damage of any nature.
As long as the website and the information and services on the website are provided free of charge, we will not be liable for any loss or damage of any nature.

View file

@ -1,6 +1,7 @@
---
index: 10
---
# Albums
you can put photos here
# Albums
you can put photos here

View file

@ -4,4 +4,4 @@ index: 4
# Database
prisma client rust, sqlite, migrations, backup
prisma client rust, sqlite, migrations, backup

View file

@ -2,7 +2,6 @@
index: 10
---
# Explorer
using the interface, features
using the interface, features

View file

@ -4,4 +4,4 @@ index: 10
# Extensions
extended functionality of Spacedrive
extended functionality of Spacedrive

View file

@ -4,4 +4,4 @@ index: 10
# Jobs
jobs are computation tasks performed by nodes in a Spacedrive network, they can be created by any node and performed by any or all nodes.
jobs are computation tasks performed by nodes in a Spacedrive network, they can be created by any node and performed by any or all nodes.

View file

@ -1,6 +1,7 @@
---
index: 1
---
# Libraries
A library is the database that Spacedrive stores all file structures and metadata. It can be synchronized with other [Nodes]()
A library is the database that Spacedrive stores all file structures and metadata. It can be synchronized with other [Nodes]()

View file

@ -4,4 +4,4 @@ index: 10
# Locations
indexing, identifying, watching, .spacedrive folder, online/offline
indexing, identifying, watching, .spacedrive folder, online/offline

View file

@ -1,10 +1,9 @@
---
index: 3
---
# Nodes
Nodes are instances of the Spacedrive core running on a device, they are able to connect to each other via a peer-to-peer network. A node is able to run many libraries simultaneously, but must be authorized per-library in order to synchronize.
p2p, connecting nodes, protocols.

View file

@ -7,8 +7,8 @@ new: true
# Objects
Objects are files discovered on your devices and drives, but can also be virtual, existing only within Spacedrive.
All metadata associated with files in Spacedrive is linked to the Object for that file.
All metadata associated with files in Spacedrive is linked to the Object for that file.
If two or more files are discovered that are identical, they are linked to the same Object in Spacedrive.
@ -18,26 +18,26 @@ Some Objects are purely virtual, meaning they have no Path and are likely only u
## Types of object
| Name | Description | Code |
| ---------------- | ------------------------------------------------------------ | ---- |
| Unknown | A file that can not be identified by the indexer | 0 |
| Document | A known filetype, but without specific support | 1 |
| Folder | A virtual filesystem directory | 2 |
| Text File | A file that contains human-readable text | 3 |
| Package | A folder that opens an application | 4 |
| Image | An image file | 5 |
| Audio | An audio file | 6 |
| Video | A video file | 7 |
| Archive | A compressed archive of data | 8 |
| Executable | An executable program or application | 9 |
| Alias | A link to another Object | 10 |
| Encrypted Bytes | Raw bytes with self contained metadata | 11 |
| Link | A link to a web page, application or Space | 12 |
| Web Page Archive | A snapshot of a webpage, with HTML, JS, images and screenshot | 13 |
| Widget | A widget is a mini app that can be placed in a Space at various sizes, associated Widget struct required | 14 |
| Album | Albums can only have one level of children, and are associated with the Album struct | 15 |
| Name | Description | Code |
| ---------------- | ---------------------------------------------------------------------------------------------------------- | ---- |
| Unknown | A file that can not be identified by the indexer | 0 |
| Document | A known filetype, but without specific support | 1 |
| Folder | A virtual filesystem directory | 2 |
| Text File | A file that contains human-readable text | 3 |
| Package | A folder that opens an application | 4 |
| Image | An image file | 5 |
| Audio | An audio file | 6 |
| Video | A video file | 7 |
| Archive | A compressed archive of data | 8 |
| Executable | An executable program or application | 9 |
| Alias | A link to another Object | 10 |
| Encrypted Bytes | Raw bytes with self contained metadata | 11 |
| Link | A link to a web page, application or Space | 12 |
| Web Page Archive | A snapshot of a webpage, with HTML, JS, images and screenshot | 13 |
| Widget | A widget is a mini app that can be placed in a Space at various sizes, associated Widget struct required | 14 |
| Album | Albums can only have one level of children, and are associated with the Album struct | 15 |
| Collection | Its like a folder, but appears like a stack of files, designed for burst photos/associated groups of files | 16 |
| Database | A database file | 17 |
| Mesh | A 3D mesh object | 18 |
| Textured Mesh | A 3D mesh object with textures | 19 |
| Entity | A rigged character | 20 |
| Database | A database file | 17 |
| Mesh | A 3D mesh object | 18 |
| Textured Mesh | A 3D mesh object with textures | 19 |
| Entity | A rigged character | 20 |

View file

@ -9,4 +9,4 @@ Spacedrive generates compressed preview media for images, videos and text files.
Preview media is stored in the Node's data folder in a single directory. Images are stored as WEBP format with their CAS id as the name.
ffmpeg, syncing, security
ffmpeg, syncing, security

View file

@ -2,7 +2,6 @@
index: 11
---
# Search
Press CTRL+F while on a Spacedrive window to access search.

View file

@ -1,10 +1,11 @@
---
index: 3
---
# Spaces
Spaces are virtual folders that can be shared publicly on the internet, or privately with friends, family and teams. Spaces contain [Objects](/docs/developers/architecture/objects) which can be physically stored on any connected Node, or by Spacedrive as a service. Objects can be organized and presented spatially, with various layouts and variable grid placements. Color theme, icon packs and typography can be customized per Space.
Objects can be added to a Space manually, or by matching a defined ruleset, similar to Tags.
Spacedrive comes with pre-defined Spaces, such as: photos, videos, screenshots, documents, .
Spacedrive comes with pre-defined Spaces, such as: photos, videos, screenshots, documents, .

View file

@ -6,4 +6,4 @@ index: 13
Spacedrive heavily incentivize using tags to organize files efficiently by giving them more functionality and easier ways to apply them, individually and in bulk.
ways to add tags, tag automation
ways to add tags, tag automation

View file

@ -3,4 +3,3 @@ index: 10
---
# Virtual Filesystem

View file

@ -1,3 +1,3 @@
---
index: 10
---
---

View file

@ -4,23 +4,27 @@ index: 500
---
# JavaScript Client
For developers who want to extend the functionality of Spacedrive, this library allows easy development of [Extensions](), providing full access to Spacedrive's functionality.
### Installation
```shell
$ npm i @spacedrive/client
```
Initialize the Spacedrive client
```ts
import spacedrive from "@spacedrive/client";
spacedrive.start()
```ts
import spacedrive from '@spacedrive/client';
spacedrive.start();
```
Add a location
```ts
const location = await spacedrive.location.create("/Users/jamie/Documents");
const location = await spacedrive.location.create('/Users/jamie/Documents');
location.scan();
```
```

View file

@ -6,37 +6,42 @@ index: 1
To get started contributing to Spacedrive, follow this guide carefully.
This project uses [Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) and [pnpm](https://pnpm.io/installation).
This project uses [Cargo](https://doc.rust-lang.org/cargo/getting-started/installation.html) and [pnpm](https://pnpm.io/installation).
## Installation
## Installation
1. **Clone repo**
```shell
git clone https://github.com/spacedriveapp/spacedrive && cd spacedrive
```
```shell
git clone https://github.com/spacedriveapp/spacedrive && cd spacedrive
```
2. **Run setup script**
**For Linux or MacOS users run:**
```shell
./.github/scripts/setup-system.sh
```
This will install FFMPEG and any other required dependencies for Spacedrive to build.
```shell
./.github/scripts/setup-system.sh
```
This will install FFMPEG and any other required dependencies for Spacedrive to build.
**...or for Windows users run using PowerShell:**
```shell
.\.github\scripts\setup-system.ps1
```
_This will install pnpm, LLVM, FFMPEG and any other required dependencies for Spacedrive to build. Ensure you run it like documented above as it expects it is executed from the root of the repository._
```shell
.\.github\scripts\setup-system.ps1
```
_This will install pnpm, LLVM, FFMPEG and any other required dependencies for Spacedrive to build. Ensure you run it like documented above as it expects it is executed from the root of the repository._
3. **Install dependencies**
```shell
pnpm i
```
```shell
pnpm i
```
4. **Run codegen & build required dependencies**
```shell
pnpm prep
```
## Running apps
```shell
pnpm prep
```
## Running apps
- **Desktop:** `pnpm desktop dev`
- **Landing:** `pnpm landing dev`
@ -53,7 +58,7 @@ To run mobile app
1. Install [Android Studio](https://developer.android.com/studio) for Android and [Xcode](https://apps.apple.com/au/app/xcode/id497799835) for IOS development
2. `./.github/scripts/setup-system.sh mobile`
_The should setup most of the dependencies for the mobile app to build._
_The should setup most of the dependencies for the mobile app to build._
3. You must also ensure you have [NDK 24.0.8215888 and CMake](https://developer.android.com/studio/projects/install-ndk#default-version) in Android Studio
4. `cd apps/mobile && pnpm i` - This is a separate workspace, you need to do this!
5. `pnpm android` - runs on Android Emulator
@ -65,4 +70,4 @@ To run mobile app
If you are having issues ensure you are using the following versions of Rust and Node:
- Rust version: **1.64.0**
- Node version: **17**
- Node version: **17**

View file

@ -6,4 +6,4 @@ index: 0
```rust
pub struct DeveloperDocumentation;
```
```

View file

@ -3,4 +3,4 @@ name: Open Source
index: 10
---
# Open Source
# Open Source

View file

@ -3,4 +3,4 @@ name: Tech Stack
index: 10
---
# Tech Stack
# Tech Stack

View file

@ -1,5 +1,5 @@
{
"name": "@sd/docs",
"description": "Allows turborepo to detect our markdown files",
"private": true
"name": "@sd/docs",
"description": "Allows turborepo to detect our markdown files",
"private": true
}

View file

@ -1 +1 @@
# Features
# Features

View file

@ -7,7 +7,7 @@ index: 0
Spacedrive is a cross-platform file manager. It connects your devices together to help you organize files from anywhere.
Beyond being an opinionated, swiss army knife file explorer, Spacedrive is a personal database. It identifies your files uniquely, understanding more file types than any operating system.
Beyond being an opinionated, swiss army knife file explorer, Spacedrive is a personal database. It identifies your files uniquely, understanding more file types than any operating system.
Create photo albums that you'll never loose, effortlessly catalogue terabytes of video, move files between devices dynamically to optimize space and redundancy, generate preview media for easy viewing, automate security and encryption—the list goes on.

View file

@ -7,4 +7,4 @@ index: 0
::: slot note Note
Spacedrive is not yet released, these docs are a work in progress. Check out our [roadmap](/roadmap) to see a timeline leading to release!
:::
:::

View file

@ -4,4 +4,3 @@ index: 0
---
# Terminology

View file

@ -11,15 +11,16 @@ Locations are places Spacedrive looks for files. You can add Locations from any
Locations can be managed from the settings. The "online" indicator shows if that Location is currently accessible from one of your devices.
## Scanning
When a Location is added it is immediately scanned. The scan happens via several phases.
1. The [Indexer](): directory structure is indexed and saved to your library's database.
2. The [Identifier](): metadata is extracted and unique identifiers generated.
3. The [Thumbnailer](): compressed previews are generated for all media and text files.
If any one of these jobs fail or the application is closed, the state is saved and it will resume when the app is relaunched.
If any one of these jobs fail or the application is closed, the state is saved and it will resume when the app is relaunched.
::: slot info
::: slot info
If you wish to pause or cancel these jobs you can do so from the [Job Manager]()
:::
@ -28,7 +29,8 @@ There is a button to trigger a full re-scan of this Location. Otherwise the loca
Deleting a location will remove the data from the database permanently.
## Archiving
::: slot warning
::: slot warning
This feature is WIP
:::
Locations can be archived, meaning the directory structure is extracted from the Spacedrive database and preserved as a standalone database file. This file can be opened by Spacedrive in the [Database]() view.
@ -36,7 +38,9 @@ Locations can be archived, meaning the directory structure is extracted from the
Archives are useful when files have been moved or deleted from a Location, but you want to keep a record of the directory structure of that Location without cluttering the Spacedrive interface. File metadata can optionally be included/excluded from the archive file.
## Dynamic Space
A slider in the Location settings allows you to allocate an amount of GB to use as redundancy for other Locations. The storage space will be filled and emptied dynamically, recent and important files will be copied as priority.
## Encrypted Space
Allocate a portion of this location to be encrypted
Allocate a portion of this location to be encrypted

View file

@ -4,11 +4,10 @@ index: 6
# Connecting Nodes
::: slot note WIP
::: slot note WIP
It is not possible to connect Nodes yet, please check our [roadmap](/roadmap).
:::
Nodes are instances of Spacedrive, commonly your devices. Currently Spacedrive supports Windows, Linux, Mac, iOS and Android.
These devices can be connected via P2P to directly and securely synchronize and move data.
Nodes are instances of Spacedrive, commonly your devices. Currently Spacedrive supports Windows, Linux, Mac, iOS and Android.
These devices can be connected via P2P to directly and securely synchronize and move data.

View file

@ -2,4 +2,4 @@
index: 11
---
# Converting Files
# Converting Files

View file

@ -4,4 +4,4 @@ index: 7
# Creating Spaces
Spaces are virtual folders, they can contain files from various locations.
Spaces are virtual folders, they can contain files from various locations.

View file

@ -2,4 +2,4 @@
index: 9
---
# Discover Duplicates
# Discover Duplicates

View file

@ -2,4 +2,4 @@
index: 10
---
# File Viewer
# File Viewer

View file

@ -4,4 +4,4 @@ index: 7
# Generate Thumbnails
![image](/thumbnails.webp)
![image](/thumbnails.webp)

View file

@ -11,4 +11,5 @@ For the convenience of finding, organizing and sharing files even when you don't
This data is heavily compressed and very portable, you can have multiple libraries and even lock and encrypt them.
## Deleting a Library
A Library can be deleted,
A Library can be deleted,

View file

@ -2,4 +2,4 @@
index: 8
---
# Managing Jobs
# Managing Jobs

View file

@ -1,3 +1,3 @@
---
index: 9
---
---

View file

@ -2,4 +2,4 @@
index: 12
---
# Photo Albums
# Photo Albums

View file

@ -1 +1 @@
# Privacy
# Privacy

View file

@ -1 +1 @@
# Security
# Security

View file

@ -11,4 +11,4 @@ pre-push:
run: pnpm eslint {staged_files}
markdown-link-check:
glob: '*.md'
run: pnpm markdown-link-check {staged_files}
run: pnpm markdown-link-check {staged_files}

View file

@ -8,7 +8,7 @@
"landing-web": "turbo run dev --parallel --filter=@sd/landing --filter=@sd/web",
"gen:migrations": "cd core && cargo prisma migrate dev",
"gen:prisma": "cd core && cargo prisma generate",
"format": "prettier --config .prettierrc.cli.js --write \"**/*.{ts,tsx,html,scss,json,yml,md}\"",
"format": "prettier --config .prettierrc.js --write \"**/*.{ts,tsx,html,scss,json,yml,md}\"",
"desktop": "pnpm --filter @sd/desktop --",
"web": "pnpm --filter @sd/web -- ",
"landing": "pnpm --filter @sd/landing -- ",

View file

@ -2,111 +2,358 @@
// This file was generated by [rspc](https://github.com/oscartbeaumont/rspc). Do not edit this file manually.
export type Procedures = {
queries:
{ key: "files.readMetadata", input: LibraryArgs<number>, result: null } |
{ key: "getNode", input: never, result: NodeState } |
{ key: "jobs.getHistory", input: LibraryArgs<null>, result: Array<JobReport> } |
{ key: "jobs.getRunning", input: LibraryArgs<null>, result: Array<JobReport> } |
{ key: "library.getStatistics", input: LibraryArgs<null>, result: Statistics } |
{ key: "library.list", input: never, result: Array<LibraryConfigWrapped> } |
{ key: "locations.getById", input: LibraryArgs<number>, result: Location | null } |
{ key: "locations.getExplorerData", input: LibraryArgs<LocationExplorerArgs>, result: ExplorerData } |
{ key: "locations.indexer_rules.get", input: LibraryArgs<number>, result: IndexerRule } |
{ key: "locations.indexer_rules.list", input: LibraryArgs<null>, result: Array<IndexerRule> } |
{ key: "locations.list", input: LibraryArgs<null>, result: Array<{ id: number, pub_id: Array<number>, node_id: number, name: string | null, local_path: string | null, total_capacity: number | null, available_capacity: number | null, filesystem: string | null, disk_type: number | null, is_removable: boolean | null, is_online: boolean, is_archived: boolean, date_created: string, node: Node }> } |
{ key: "tags.get", input: LibraryArgs<number>, result: Tag | null } |
{ key: "tags.getExplorerData", input: LibraryArgs<number>, result: ExplorerData } |
{ key: "tags.getForObject", input: LibraryArgs<number>, result: Array<Tag> } |
{ key: "tags.list", input: LibraryArgs<null>, result: Array<Tag> } |
{ key: "version", input: never, result: string } |
{ key: "volumes.list", input: never, result: Array<Volume> },
mutations:
{ key: "files.delete", input: LibraryArgs<number>, result: null } |
{ key: "files.setFavorite", input: LibraryArgs<SetFavoriteArgs>, result: null } |
{ key: "files.setNote", input: LibraryArgs<SetNoteArgs>, result: null } |
{ key: "jobs.generateThumbsForLocation", input: LibraryArgs<GenerateThumbsForLocationArgs>, result: null } |
{ key: "jobs.identifyUniqueFiles", input: LibraryArgs<IdentifyUniqueFilesArgs>, result: null } |
{ key: "library.create", input: string, result: LibraryConfigWrapped } |
{ key: "library.delete", input: string, result: null } |
{ key: "library.edit", input: EditLibraryArgs, result: null } |
{ key: "locations.create", input: LibraryArgs<LocationCreateArgs>, result: null } |
{ key: "locations.delete", input: LibraryArgs<number>, result: null } |
{ key: "locations.fullRescan", input: LibraryArgs<number>, result: null } |
{ key: "locations.indexer_rules.create", input: LibraryArgs<IndexerRuleCreateArgs>, result: IndexerRule } |
{ key: "locations.indexer_rules.delete", input: LibraryArgs<number>, result: null } |
{ key: "locations.quickRescan", input: LibraryArgs<null>, result: null } |
{ key: "locations.update", input: LibraryArgs<LocationUpdateArgs>, result: null } |
{ key: "tags.assign", input: LibraryArgs<TagAssignArgs>, result: null } |
{ key: "tags.create", input: LibraryArgs<TagCreateArgs>, result: Tag } |
{ key: "tags.delete", input: LibraryArgs<number>, result: null } |
{ key: "tags.update", input: LibraryArgs<TagUpdateArgs>, result: null },
subscriptions:
{ key: "invalidateQuery", input: never, result: InvalidateOperationEvent } |
{ key: "jobs.newThumbnail", input: LibraryArgs<null>, result: string }
queries:
| { key: 'files.readMetadata'; input: LibraryArgs<number>; result: null }
| { key: 'getNode'; input: never; result: NodeState }
| { key: 'jobs.getHistory'; input: LibraryArgs<null>; result: Array<JobReport> }
| { key: 'jobs.getRunning'; input: LibraryArgs<null>; result: Array<JobReport> }
| { key: 'library.getStatistics'; input: LibraryArgs<null>; result: Statistics }
| { key: 'library.list'; input: never; result: Array<LibraryConfigWrapped> }
| { key: 'locations.getById'; input: LibraryArgs<number>; result: Location | null }
| {
key: 'locations.getExplorerData';
input: LibraryArgs<LocationExplorerArgs>;
result: ExplorerData;
}
| { key: 'locations.indexer_rules.get'; input: LibraryArgs<number>; result: IndexerRule }
| { key: 'locations.indexer_rules.list'; input: LibraryArgs<null>; result: Array<IndexerRule> }
| {
key: 'locations.list';
input: LibraryArgs<null>;
result: Array<{
id: number;
pub_id: Array<number>;
node_id: number;
name: string | null;
local_path: string | null;
total_capacity: number | null;
available_capacity: number | null;
filesystem: string | null;
disk_type: number | null;
is_removable: boolean | null;
is_online: boolean;
is_archived: boolean;
date_created: string;
node: Node;
}>;
}
| { key: 'tags.get'; input: LibraryArgs<number>; result: Tag | null }
| { key: 'tags.getExplorerData'; input: LibraryArgs<number>; result: ExplorerData }
| { key: 'tags.getForObject'; input: LibraryArgs<number>; result: Array<Tag> }
| { key: 'tags.list'; input: LibraryArgs<null>; result: Array<Tag> }
| { key: 'version'; input: never; result: string }
| { key: 'volumes.list'; input: never; result: Array<Volume> };
mutations:
| { key: 'files.delete'; input: LibraryArgs<number>; result: null }
| { key: 'files.setFavorite'; input: LibraryArgs<SetFavoriteArgs>; result: null }
| { key: 'files.setNote'; input: LibraryArgs<SetNoteArgs>; result: null }
| {
key: 'jobs.generateThumbsForLocation';
input: LibraryArgs<GenerateThumbsForLocationArgs>;
result: null;
}
| { key: 'jobs.identifyUniqueFiles'; input: LibraryArgs<IdentifyUniqueFilesArgs>; result: null }
| { key: 'library.create'; input: string; result: LibraryConfigWrapped }
| { key: 'library.delete'; input: string; result: null }
| { key: 'library.edit'; input: EditLibraryArgs; result: null }
| { key: 'locations.create'; input: LibraryArgs<LocationCreateArgs>; result: null }
| { key: 'locations.delete'; input: LibraryArgs<number>; result: null }
| { key: 'locations.fullRescan'; input: LibraryArgs<number>; result: null }
| {
key: 'locations.indexer_rules.create';
input: LibraryArgs<IndexerRuleCreateArgs>;
result: IndexerRule;
}
| { key: 'locations.indexer_rules.delete'; input: LibraryArgs<number>; result: null }
| { key: 'locations.quickRescan'; input: LibraryArgs<null>; result: null }
| { key: 'locations.update'; input: LibraryArgs<LocationUpdateArgs>; result: null }
| { key: 'tags.assign'; input: LibraryArgs<TagAssignArgs>; result: null }
| { key: 'tags.create'; input: LibraryArgs<TagCreateArgs>; result: Tag }
| { key: 'tags.delete'; input: LibraryArgs<number>; result: null }
| { key: 'tags.update'; input: LibraryArgs<TagUpdateArgs>; result: null };
subscriptions:
| { key: 'invalidateQuery'; input: never; result: InvalidateOperationEvent }
| { key: 'jobs.newThumbnail'; input: LibraryArgs<null>; result: string };
};
export interface ConfigMetadata { version: string | null }
export interface ConfigMetadata {
version: string | null;
}
export interface EditLibraryArgs { id: string, name: string | null, description: string | null }
export interface EditLibraryArgs {
id: string;
name: string | null;
description: string | null;
}
export type ExplorerContext = { type: "Location" } & Location | { type: "Tag" } & Tag
export type ExplorerContext = ({ type: 'Location' } & Location) | ({ type: 'Tag' } & Tag);
export interface ExplorerData { context: ExplorerContext, items: Array<ExplorerItem> }
export interface ExplorerData {
context: ExplorerContext;
items: Array<ExplorerItem>;
}
export type ExplorerItem = { type: "Path" } & { id: number, is_dir: boolean, location_id: number, materialized_path: string, name: string, extension: string | null, object_id: number | null, parent_id: number | null, key_id: number | null, date_created: string, date_modified: string, date_indexed: string, object: Object | null } | { type: "Object" } & { id: number, cas_id: string, integrity_checksum: string | null, name: string | null, extension: string | null, kind: number, size_in_bytes: string, key_id: number | null, hidden: boolean, favorite: boolean, important: boolean, has_thumbnail: boolean, has_thumbstrip: boolean, has_video_preview: boolean, ipfs_id: string | null, note: string | null, date_created: string, date_modified: string, date_indexed: string, file_paths: Array<FilePath> }
export type ExplorerItem =
| ({ type: 'Path' } & {
id: number;
is_dir: boolean;
location_id: number;
materialized_path: string;
name: string;
extension: string | null;
object_id: number | null;
parent_id: number | null;
key_id: number | null;
date_created: string;
date_modified: string;
date_indexed: string;
object: Object | null;
})
| ({ type: 'Object' } & {
id: number;
cas_id: string;
integrity_checksum: string | null;
name: string | null;
extension: string | null;
kind: number;
size_in_bytes: string;
key_id: number | null;
hidden: boolean;
favorite: boolean;
important: boolean;
has_thumbnail: boolean;
has_thumbstrip: boolean;
has_video_preview: boolean;
ipfs_id: string | null;
note: string | null;
date_created: string;
date_modified: string;
date_indexed: string;
file_paths: Array<FilePath>;
});
export interface FilePath { id: number, is_dir: boolean, location_id: number, materialized_path: string, name: string, extension: string | null, object_id: number | null, parent_id: number | null, key_id: number | null, date_created: string, date_modified: string, date_indexed: string }
export interface FilePath {
id: number;
is_dir: boolean;
location_id: number;
materialized_path: string;
name: string;
extension: string | null;
object_id: number | null;
parent_id: number | null;
key_id: number | null;
date_created: string;
date_modified: string;
date_indexed: string;
}
export interface GenerateThumbsForLocationArgs { id: number, path: string }
export interface GenerateThumbsForLocationArgs {
id: number;
path: string;
}
export interface IdentifyUniqueFilesArgs { id: number, path: string }
export interface IdentifyUniqueFilesArgs {
id: number;
path: string;
}
export interface IndexerRule { id: number, kind: number, name: string, parameters: Array<number>, date_created: string, date_modified: string }
export interface IndexerRule {
id: number;
kind: number;
name: string;
parameters: Array<number>;
date_created: string;
date_modified: string;
}
export interface IndexerRuleCreateArgs { kind: RuleKind, name: string, parameters: Array<number> }
export interface IndexerRuleCreateArgs {
kind: RuleKind;
name: string;
parameters: Array<number>;
}
export interface InvalidateOperationEvent { key: string, arg: any }
export interface InvalidateOperationEvent {
key: string;
arg: any;
}
export interface JobReport { id: string, name: string, data: Array<number> | null, metadata: any | null, date_created: string, date_modified: string, status: JobStatus, task_count: number, completed_task_count: number, message: string, seconds_elapsed: number }
export interface JobReport {
id: string;
name: string;
data: Array<number> | null;
metadata: any | null;
date_created: string;
date_modified: string;
status: JobStatus;
task_count: number;
completed_task_count: number;
message: string;
seconds_elapsed: number;
}
export type JobStatus = "Queued" | "Running" | "Completed" | "Canceled" | "Failed" | "Paused"
export type JobStatus = 'Queued' | 'Running' | 'Completed' | 'Canceled' | 'Failed' | 'Paused';
export interface LibraryArgs<T> { library_id: string, arg: T }
export interface LibraryArgs<T> {
library_id: string;
arg: T;
}
export interface LibraryConfig { version: string | null, name: string, description: string }
export interface LibraryConfig {
version: string | null;
name: string;
description: string;
}
export interface LibraryConfigWrapped { uuid: string, config: LibraryConfig }
export interface LibraryConfigWrapped {
uuid: string;
config: LibraryConfig;
}
export interface Location { id: number, pub_id: Array<number>, node_id: number, name: string | null, local_path: string | null, total_capacity: number | null, available_capacity: number | null, filesystem: string | null, disk_type: number | null, is_removable: boolean | null, is_online: boolean, is_archived: boolean, date_created: string }
export interface Location {
id: number;
pub_id: Array<number>;
node_id: number;
name: string | null;
local_path: string | null;
total_capacity: number | null;
available_capacity: number | null;
filesystem: string | null;
disk_type: number | null;
is_removable: boolean | null;
is_online: boolean;
is_archived: boolean;
date_created: string;
}
export interface LocationCreateArgs { path: string, indexer_rules_ids: Array<number> }
export interface LocationCreateArgs {
path: string;
indexer_rules_ids: Array<number>;
}
export interface LocationExplorerArgs { location_id: number, path: string, limit: number, cursor: string | null }
export interface LocationExplorerArgs {
location_id: number;
path: string;
limit: number;
cursor: string | null;
}
export interface LocationUpdateArgs { id: number, name: string | null, indexer_rules_ids: Array<number> }
export interface LocationUpdateArgs {
id: number;
name: string | null;
indexer_rules_ids: Array<number>;
}
export interface Node { id: number, pub_id: Array<number>, name: string, platform: number, version: string | null, last_seen: string, timezone: string | null, date_created: string }
export interface Node {
id: number;
pub_id: Array<number>;
name: string;
platform: number;
version: string | null;
last_seen: string;
timezone: string | null;
date_created: string;
}
export interface NodeConfig { version: string | null, id: string, name: string, p2p_port: number | null }
export interface NodeConfig {
version: string | null;
id: string;
name: string;
p2p_port: number | null;
}
export interface NodeState { version: string | null, id: string, name: string, p2p_port: number | null, data_path: string }
export interface NodeState {
version: string | null;
id: string;
name: string;
p2p_port: number | null;
data_path: string;
}
export interface Object { id: number, cas_id: string, integrity_checksum: string | null, name: string | null, extension: string | null, kind: number, size_in_bytes: string, key_id: number | null, hidden: boolean, favorite: boolean, important: boolean, has_thumbnail: boolean, has_thumbstrip: boolean, has_video_preview: boolean, ipfs_id: string | null, note: string | null, date_created: string, date_modified: string, date_indexed: string }
export interface Object {
id: number;
cas_id: string;
integrity_checksum: string | null;
name: string | null;
extension: string | null;
kind: number;
size_in_bytes: string;
key_id: number | null;
hidden: boolean;
favorite: boolean;
important: boolean;
has_thumbnail: boolean;
has_thumbstrip: boolean;
has_video_preview: boolean;
ipfs_id: string | null;
note: string | null;
date_created: string;
date_modified: string;
date_indexed: string;
}
export type RuleKind = "AcceptFilesByGlob" | "RejectFilesByGlob" | "AcceptIfChildrenDirectoriesArePresent" | "RejectIfChildrenDirectoriesArePresent"
export type RuleKind =
| 'AcceptFilesByGlob'
| 'RejectFilesByGlob'
| 'AcceptIfChildrenDirectoriesArePresent'
| 'RejectIfChildrenDirectoriesArePresent';
export interface SetFavoriteArgs { id: number, favorite: boolean }
export interface SetFavoriteArgs {
id: number;
favorite: boolean;
}
export interface SetNoteArgs { id: number, note: string | null }
export interface SetNoteArgs {
id: number;
note: string | null;
}
export interface Statistics { id: number, date_captured: string, total_object_count: number, library_db_size: string, total_bytes_used: string, total_bytes_capacity: string, total_unique_bytes: string, total_bytes_free: string, preview_media_bytes: string }
export interface Statistics {
id: number;
date_captured: string;
total_object_count: number;
library_db_size: string;
total_bytes_used: string;
total_bytes_capacity: string;
total_unique_bytes: string;
total_bytes_free: string;
preview_media_bytes: string;
}
export interface Tag { id: number, pub_id: Array<number>, name: string | null, color: string | null, total_objects: number | null, redundancy_goal: number | null, date_created: string, date_modified: string }
export interface Tag {
id: number;
pub_id: Array<number>;
name: string | null;
color: string | null;
total_objects: number | null;
redundancy_goal: number | null;
date_created: string;
date_modified: string;
}
export interface TagAssignArgs { object_id: number, tag_id: number, unassign: boolean }
export interface TagAssignArgs {
object_id: number;
tag_id: number;
unassign: boolean;
}
export interface TagCreateArgs { name: string, color: string }
export interface TagCreateArgs {
name: string;
color: string;
}
export interface TagUpdateArgs { id: number, name: string | null, color: string | null }
export interface TagUpdateArgs {
id: number;
name: string | null;
color: string | null;
}
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

@ -1,96 +1,96 @@
{
"name": "@sd/interface",
"version": "1.0.0",
"license": "GPL-3.0-only",
"private": true,
"main": "src/index.ts",
"exports": {
".": "./src/index.ts",
"./types": "./src/types",
"./assets/*": "./src/assets/*",
"./components/*": "./src/components/*"
},
"scripts": {
"icons": "./scripts/generateSvgImports.mjs",
"lint": "eslint src/**/*.{ts,tsx} && tsc --noEmit"
},
"dependencies": {
"@fontsource/inter": "^4.5.13",
"@headlessui/react": "^1.7.3",
"@heroicons/react": "^2.0.12",
"@radix-ui/react-dialog": "^1.0.0",
"@radix-ui/react-dropdown-menu": "^1.0.0",
"@radix-ui/react-icons": "^1.1.1",
"@radix-ui/react-progress": "^1.0.0",
"@radix-ui/react-slider": "^1.0.0",
"@radix-ui/react-tabs": "^1.0.0",
"@radix-ui/react-toast": "^1.0.0",
"@radix-ui/react-tooltip": "^1.0.0",
"@sd/assets": "workspace:*",
"@sd/client": "workspace:*",
"@sd/ui": "workspace:*",
"@tailwindcss/forms": "^0.5.3",
"@tanstack/react-query": "^4.10.1",
"@tanstack/react-query-devtools": "^4.10.1",
"@tanstack/react-virtual": "3.0.0-beta.18",
"@vitejs/plugin-react": "^2.1.0",
"autoprefixer": "^10.4.12",
"byte-size": "^8.1.0",
"clsx": "^1.2.1",
"date-fns": "^2.29.3",
"dayjs": "^1.11.5",
"immer": "^9.0.15",
"jotai": "^1.8.4",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"phosphor-react": "^1.4.1",
"pretty-bytes": "^6.0.0",
"react": "^18.2.0",
"react-colorful": "^5.6.1",
"react-countup": "^6.3.1",
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.2",
"react-error-boundary": "^3.1.4",
"react-hook-form": "^7.36.1",
"react-hotkeys-hook": "^3.4.7",
"react-json-view": "^1.21.3",
"react-loading-icons": "^1.1.0",
"react-loading-skeleton": "^3.1.0",
"react-portal": "^4.2.2",
"react-query": "^3.39.2",
"react-router": "6.4.2",
"react-router-dom": "6.4.2",
"react-scrollbars-custom": "^4.1.1",
"react-spline": "^1.2.1",
"react-transition-group": "^4.4.5",
"react-virtuoso": "^2.19.1",
"rooks": "^5.14.0",
"tailwindcss": "^3.1.8",
"use-count-up": "^3.0.1",
"use-debounce": "^8.0.4",
"valtio": "^1.7.0",
"valtio-persist": "^1.0.2",
"zod": "^3.19.1",
"zustand": "4.1.1"
},
"devDependencies": {
"@sd/config": "workspace:*",
"@types/babel-core": "^6.25.7",
"@types/byte-size": "^8.1.0",
"@types/lodash": "^4.14.186",
"@types/node": "^18.8.2",
"@types/pretty-bytes": "^5.2.0",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"@types/react-router-dom": "^5.3.3",
"@types/react-table": "^7.7.12",
"@types/react-window": "^1.8.5",
"@types/tailwindcss": "^3.1.0",
"@vitejs/plugin-react": "^1.3.1",
"concurrently": "^7.4.0",
"prettier": "^2.7.1",
"typescript": "^4.8.4",
"vite": "^3.1.4",
"vite-plugin-svgr": "^2.2.1"
}
"name": "@sd/interface",
"version": "1.0.0",
"license": "GPL-3.0-only",
"private": true,
"main": "src/index.ts",
"exports": {
".": "./src/index.ts",
"./types": "./src/types",
"./assets/*": "./src/assets/*",
"./components/*": "./src/components/*"
},
"scripts": {
"icons": "./scripts/generateSvgImports.mjs",
"lint": "eslint src/**/*.{ts,tsx} && tsc --noEmit"
},
"dependencies": {
"@fontsource/inter": "^4.5.13",
"@headlessui/react": "^1.7.3",
"@heroicons/react": "^2.0.12",
"@radix-ui/react-dialog": "^1.0.0",
"@radix-ui/react-dropdown-menu": "^1.0.0",
"@radix-ui/react-icons": "^1.1.1",
"@radix-ui/react-progress": "^1.0.0",
"@radix-ui/react-slider": "^1.0.0",
"@radix-ui/react-tabs": "^1.0.0",
"@radix-ui/react-toast": "^1.0.0",
"@radix-ui/react-tooltip": "^1.0.0",
"@sd/assets": "workspace:*",
"@sd/client": "workspace:*",
"@sd/ui": "workspace:*",
"@tailwindcss/forms": "^0.5.3",
"@tanstack/react-query": "^4.10.1",
"@tanstack/react-query-devtools": "^4.10.1",
"@tanstack/react-virtual": "3.0.0-beta.18",
"@vitejs/plugin-react": "^2.1.0",
"autoprefixer": "^10.4.12",
"byte-size": "^8.1.0",
"clsx": "^1.2.1",
"date-fns": "^2.29.3",
"dayjs": "^1.11.5",
"immer": "^9.0.15",
"jotai": "^1.8.4",
"lodash": "^4.17.21",
"moment": "^2.29.4",
"phosphor-react": "^1.4.1",
"pretty-bytes": "^6.0.0",
"react": "^18.2.0",
"react-colorful": "^5.6.1",
"react-countup": "^6.3.1",
"react-dom": "^18.2.0",
"react-dropzone": "^14.2.2",
"react-error-boundary": "^3.1.4",
"react-hook-form": "^7.36.1",
"react-hotkeys-hook": "^3.4.7",
"react-json-view": "^1.21.3",
"react-loading-icons": "^1.1.0",
"react-loading-skeleton": "^3.1.0",
"react-portal": "^4.2.2",
"react-query": "^3.39.2",
"react-router": "6.4.2",
"react-router-dom": "6.4.2",
"react-scrollbars-custom": "^4.1.1",
"react-spline": "^1.2.1",
"react-transition-group": "^4.4.5",
"react-virtuoso": "^2.19.1",
"rooks": "^5.14.0",
"tailwindcss": "^3.1.8",
"use-count-up": "^3.0.1",
"use-debounce": "^8.0.4",
"valtio": "^1.7.0",
"valtio-persist": "^1.0.2",
"zod": "^3.19.1",
"zustand": "4.1.1"
},
"devDependencies": {
"@sd/config": "workspace:*",
"@types/babel-core": "^6.25.7",
"@types/byte-size": "^8.1.0",
"@types/lodash": "^4.14.186",
"@types/node": "^18.8.2",
"@types/pretty-bytes": "^5.2.0",
"@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6",
"@types/react-router-dom": "^5.3.3",
"@types/react-table": "^7.7.12",
"@types/react-window": "^1.8.5",
"@types/tailwindcss": "^3.1.0",
"@vitejs/plugin-react": "^1.3.1",
"concurrently": "^7.4.0",
"prettier": "^2.7.1",
"typescript": "^4.8.4",
"vite": "^3.1.4",
"vite-plugin-svgr": "^2.2.1"
}
}

View file

@ -1,8 +1,9 @@
import { useCurrentLibrary, useInvalidateQuery } from '@sd/client';
import { Suspense, lazy } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
import { AppLayout } from './AppLayout';
import { useKeybindHandler } from './hooks/useKeyboardHandler';
import { useCurrentLibrary, useInvalidateQuery } from '@sd/client';
import { lazy, Suspense } from 'react';
import { Navigate, Route, Routes } from 'react-router-dom';
const DebugScreen = lazy(() => import('./screens/Debug'));
const SettingsScreen = lazy(() => import('./screens/settings/Settings'));

View file

@ -1,5 +1,3 @@
import { Folder } from '../icons/Folder';
import { isObject, isPath } from './utils';
import videoSvg from '@sd/assets/svgs/video.svg';
import zipSvg from '@sd/assets/svgs/zip.svg';
import { getExplorerStore, usePlatform } from '@sd/client';
@ -10,6 +8,9 @@ import { useState } from 'react';
import { Suspense, lazy, useMemo } from 'react';
import { useSnapshot } from 'valtio';
import { Folder } from '../icons/Folder';
import { isObject, isPath } from './utils';
interface Props {
data: ExplorerItem;
size: number;

View file

@ -1,11 +1,4 @@
// import types from '../../constants/file-types.json';
import { Tooltip } from '../tooltip/Tooltip';
import FileThumb from './FileThumb';
import { Divider } from './inspector/Divider';
import FavoriteButton from './inspector/FavoriteButton';
import { MetaItem } from './inspector/MetaItem';
import Note from './inspector/Note';
import { isObject } from './utils';
import { ShareIcon } from '@heroicons/react/24/solid';
import { useLibraryQuery } from '@sd/client';
import { ExplorerContext, ExplorerItem } from '@sd/client';
@ -16,6 +9,14 @@ import dayjs from 'dayjs';
import { Link } from 'phosphor-react';
import { useEffect, useState } from 'react';
import { Tooltip } from '../tooltip/Tooltip';
import FileThumb from './FileThumb';
import { Divider } from './inspector/Divider';
import FavoriteButton from './inspector/FavoriteButton';
import { MetaItem } from './inspector/MetaItem';
import Note from './inspector/Note';
import { isObject } from './utils';
interface Props {
context?: ExplorerContext;
data?: ExplorerItem;

View file

@ -1,6 +1,3 @@
import FileItem from './FileItem';
import FileRow from './FileRow';
import { isPath } from './utils';
import { ExplorerLayoutMode, getExplorerStore, useExplorerStore } from '@sd/client';
import { ExplorerContext, ExplorerItem } from '@sd/client';
import { useVirtualizer } from '@tanstack/react-virtual';
@ -8,6 +5,10 @@ import { memo, useCallback, useEffect, useLayoutEffect, useRef, useState } from
import { useSearchParams } from 'react-router-dom';
import { useKey, useOnWindowResize } from 'rooks';
import FileItem from './FileItem';
import FileRow from './FileRow';
import { isPath } from './utils';
const TOP_BAR_HEIGHT = 50;
const GRID_TEXT_AREA_HEIGHT = 25;

View file

@ -132,22 +132,22 @@ body {
}
.picker {
position: relative;
position: relative;
}
.swatch {
width: 28px;
height: 28px;
border-radius: 8px;
border: 3px solid #fff;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), inset 0 0 0 1px rgba(0, 0, 0, 0.1);
cursor: pointer;
width: 28px;
height: 28px;
border-radius: 8px;
border: 3px solid #fff;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1), inset 0 0 0 1px rgba(0, 0, 0, 0.1);
cursor: pointer;
}
.popover {
position: absolute;
top: calc(100% + 2px);
left: 0;
border-radius: 9px;
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}
position: absolute;
top: calc(100% + 2px);
left: 0;
border-radius: 9px;
box-shadow: 0 6px 12px rgba(0, 0, 0, 0.15);
}

View file

@ -1,16 +1,14 @@
{
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"build": {
"outputs": [
"dist/**"
]
},
"lint": {
"outputs": []
},
"dev": {
"cache": false
}
}
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"build": {
"outputs": ["dist/**"]
},
"lint": {
"outputs": []
},
"dev": {
"cache": false
}
}
}