mirror of
https://github.com/spacedriveapp/spacedrive.git
synced 2026-05-19 13:55:40 -04:00
[ENG-469] Make Prettier and ESLint work together (#706)
* Make Prettier and ESLint work together - Resolve conflicts between Prettier and ESLint regarding indentation and Tailwind rules order - Add `.editorconfig` to standardize basic formatting options across tools and editors - Add `.gitattributes` to hide `pnpm-lock.yaml` in `git diff` output - Include EditorConfig in the recommended extensions for VSCode - Replace some instances of `pnpm exec <command>` with `pnpm <command>` - Remove superfluous Tauri config for Linux * Revert Prettier changes (it was working correctly before) - Update ESLint to read Tailwind config from absolute path - Remove redundant Prettier dependency from subprojects - Specify the source folder for the lint script in subprojects * use mobile's tailwind config with eslint * pnpm format + pnpm lint:fix --------- Co-authored-by: Utku Bakir <74243531+utkubakir@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
18938a89fc
commit
50442ede3e
56
.editorconfig
Normal file
56
.editorconfig
Normal file
@@ -0,0 +1,56 @@
|
||||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
# https://github.com/jokeyrhyme/standard-editorconfig
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# defaults
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
indent_style = tab
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# BATS: https://github.com/bats-core/bats-core
|
||||
# https://github.com/bats-core/bats-core/master/.editorconfig
|
||||
[*.bats]
|
||||
insert_final_newline = true
|
||||
max_line_length = 80
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# CSS
|
||||
# https://google.github.io/styleguide/htmlcssguide.xml#General_Formatting_Rules
|
||||
# http://cssguidelin.es/#syntax-and-formatting
|
||||
[*.css]
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# HTML
|
||||
# https://google.github.io/styleguide/htmlcssguide.xml#General_Formatting_Rules
|
||||
[*.{htm,html}]
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
# JavaScript, JSON, JSX, JavaScript Modules, TypeScript
|
||||
# https://github.com/feross/standard
|
||||
# https://prettier.io
|
||||
[*.{cjs,js,json,jsx,mjs,ts,tsx}]
|
||||
indent_size = 4
|
||||
|
||||
# Kotlin
|
||||
# https://android.github.io/kotlin-guides/style.html#indentation
|
||||
[*.{kt,kts}]
|
||||
indent_size = 4
|
||||
|
||||
# Python
|
||||
# https://www.python.org/dev/peps/pep-0008/#code-lay-out
|
||||
[*.py]
|
||||
indent_size = 4
|
||||
|
||||
# Rust
|
||||
# https://github.com/rust-lang/rust/blob/master/src/doc/style/style/whitespace.md
|
||||
[*.rs]
|
||||
indent_size = 4
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = true
|
||||
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
pnpm-lock.yaml -diff
|
||||
package-lock.json -diff
|
||||
3
.vscode/extensions.json
vendored
3
.vscode/extensions.json
vendored
@@ -2,6 +2,7 @@
|
||||
"recommendations": [
|
||||
"tauri-apps.tauri-vscode",
|
||||
"rust-lang.rust-analyzer",
|
||||
"oscartbeaumont.rspc-vscode"
|
||||
"oscartbeaumont.rspc-vscode",
|
||||
"EditorConfig.EditorConfig"
|
||||
]
|
||||
}
|
||||
|
||||
6
.vscode/launch.json
vendored
6
.vscode/launch.json
vendored
@@ -24,7 +24,11 @@
|
||||
"request": "launch",
|
||||
"name": "Tauri Production Debug",
|
||||
"cargo": {
|
||||
"args": ["build", "--release", "--manifest-path=./apps/desktop/src-tauri/Cargo.toml"],
|
||||
"args": [
|
||||
"build",
|
||||
"--release",
|
||||
"--manifest-path=./apps/desktop/src-tauri/Cargo.toml"
|
||||
],
|
||||
"problemMatcher": "$rustc"
|
||||
},
|
||||
"sourceLanguages": ["rust"],
|
||||
|
||||
10
.vscode/settings.json
vendored
10
.vscode/settings.json
vendored
@@ -54,10 +54,14 @@
|
||||
// "apps/mobile/ios": true
|
||||
},
|
||||
"eslint.workingDirectories": [
|
||||
"apps/desktop",
|
||||
"apps/landing",
|
||||
"apps/mobile",
|
||||
"packages/ui",
|
||||
"interface",
|
||||
"packages/client",
|
||||
"packages/interface"
|
||||
]
|
||||
"packages/config",
|
||||
"packages/ui"
|
||||
],
|
||||
"eslint.packageManager": "pnpm",
|
||||
"eslint.lintTask.enable": true
|
||||
}
|
||||
|
||||
5
.vscode/tasks.json
vendored
5
.vscode/tasks.json
vendored
@@ -47,7 +47,10 @@
|
||||
{
|
||||
"type": "cargo",
|
||||
"command": "run",
|
||||
"args": ["--manifest-path=./apps/desktop/src-tauri/Cargo.toml", "--no-default-features"],
|
||||
"args": [
|
||||
"--manifest-path=./apps/desktop/src-tauri/Cargo.toml",
|
||||
"--no-default-features"
|
||||
],
|
||||
"env": {
|
||||
"RUST_BACKTRACE": "short"
|
||||
},
|
||||
|
||||
7
apps/desktop/.eslintrc.js
Normal file
7
apps/desktop/.eslintrc.js
Normal file
@@ -0,0 +1,7 @@
|
||||
module.exports = {
|
||||
extends: [require.resolve('@sd/config/eslint/web.js')],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
};
|
||||
@@ -11,7 +11,8 @@
|
||||
"tauri": "tauri",
|
||||
"build": "node ./src-tauri/build.js",
|
||||
"dmg": "open ../../target/release/bundle/dmg/",
|
||||
"typecheck": "tsc -b"
|
||||
"typecheck": "tsc -b",
|
||||
"lint": "eslint src --cache"
|
||||
},
|
||||
"dependencies": {
|
||||
"@rspc/client": "^0.0.0-main-7c0a67c1",
|
||||
@@ -33,7 +34,6 @@
|
||||
"@types/react": "^18.0.21",
|
||||
"@types/react-dom": "^18.0.6",
|
||||
"@vitejs/plugin-react": "^2.1.0",
|
||||
"prettier": "^2.7.1",
|
||||
"react-devtools": "^4.27.2",
|
||||
"sass": "^1.55.0",
|
||||
"typescript": "^4.8.4",
|
||||
|
||||
@@ -5,7 +5,7 @@ process.env.BACKGROUND_FILE = path.join(__dirname, './dmg-background.png');
|
||||
process.env.BACKGROUND_FILE_NAME = path.basename(process.env.BACKGROUND_FILE);
|
||||
process.env.BACKGROUND_CLAUSE = `set background picture of opts to file ".background:${process.env.BACKGROUND_FILE_NAME}"`;
|
||||
|
||||
const child = spawn('pnpm', ['exec', 'tauri', 'build']);
|
||||
const child = spawn('pnpm', ['tauri', 'build']);
|
||||
child.stdout.on('data', (data) => console.log(data.toString()));
|
||||
child.stderr.on('data', (data) => console.error(data.toString()));
|
||||
child.on('exit', (code) => {
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"distDir": "../dist",
|
||||
"devPath": "http://localhost:8001",
|
||||
"beforeDevCommand": "pnpm dev-vite",
|
||||
"beforeBuildCommand": "pnpm exec vite build"
|
||||
"beforeBuildCommand": "pnpm vite build"
|
||||
},
|
||||
"tauri": {
|
||||
"macOSPrivateApi": true,
|
||||
|
||||
@@ -1,84 +0,0 @@
|
||||
{
|
||||
"package": {
|
||||
"productName": "Spacedrive",
|
||||
"version": "0.1.0"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
"devPath": "http://localhost:8001",
|
||||
"beforeDevCommand": "pnpm dev-vite",
|
||||
"beforeBuildCommand": "pnpm exec vite build"
|
||||
},
|
||||
"tauri": {
|
||||
"macOSPrivateApi": true,
|
||||
"bundle": {
|
||||
"active": true,
|
||||
"targets": "all",
|
||||
"identifier": "com.spacedrive.desktop",
|
||||
"icon": [
|
||||
"icons/32x32.png",
|
||||
"icons/128x128.png",
|
||||
"icons/128x128@2x.png",
|
||||
"icons/icon.icns",
|
||||
"icons/icon.ico"
|
||||
],
|
||||
"resources": [],
|
||||
"externalBin": [],
|
||||
"copyright": "Spacedrive Technology Inc.",
|
||||
"shortDescription": "The universal file manager.",
|
||||
"longDescription": "A cross-platform universal file explorer, powered by an open-source virtual distributed filesystem.",
|
||||
"deb": {
|
||||
"depends": []
|
||||
},
|
||||
"macOS": {
|
||||
"frameworks": [],
|
||||
"minimumSystemVersion": "10.14",
|
||||
"exceptionDomain": "",
|
||||
"signingIdentity": null,
|
||||
"entitlements": null
|
||||
},
|
||||
"windows": {
|
||||
"certificateThumbprint": null,
|
||||
"digestAlgorithm": "sha256",
|
||||
"timestampUrl": ""
|
||||
}
|
||||
},
|
||||
"updater": {
|
||||
"active": false
|
||||
},
|
||||
"allowlist": {
|
||||
"all": true,
|
||||
"protocol": {
|
||||
"assetScope": ["*"]
|
||||
},
|
||||
"os": {
|
||||
"all": true
|
||||
},
|
||||
"dialog": {
|
||||
"all": true,
|
||||
"open": true,
|
||||
"save": true
|
||||
}
|
||||
},
|
||||
"windows": [
|
||||
{
|
||||
"title": "Spacedrive",
|
||||
"width": 1200,
|
||||
"height": 725,
|
||||
"minWidth": 700,
|
||||
"minHeight": 500,
|
||||
"resizable": true,
|
||||
"fullscreen": false,
|
||||
"alwaysOnTop": false,
|
||||
"focus": false,
|
||||
"fileDropEnabled": false,
|
||||
"decorations": true,
|
||||
"transparent": true,
|
||||
"center": true
|
||||
}
|
||||
],
|
||||
"security": {
|
||||
"csp": "default-src spacedrive: asset: https://asset.localhost blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self' img-src: 'self'"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,5 +3,13 @@ module.exports = {
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
},
|
||||
rules: {
|
||||
'tailwindcss/classnames-order': [
|
||||
'warn',
|
||||
{
|
||||
config: './tailwind.config.js'
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"ios": "expo run:ios",
|
||||
"xcode": "open ios/spacedrive.xcworkspace",
|
||||
"android-studio": "open -a '/Applications/Android Studio.app' ./android",
|
||||
"lint": "eslint src",
|
||||
"lint": "eslint src --cache",
|
||||
"typecheck": "tsc -b",
|
||||
"clean:android": "cd android && ./gradlew clean && cd ../",
|
||||
"clean:ios": "cd ios && xcodebuild clean && cd ../"
|
||||
|
||||
@@ -107,7 +107,7 @@ function AppContainer() {
|
||||
const { id } = useSnapshot(currentLibraryStore);
|
||||
|
||||
return (
|
||||
<SafeAreaProvider style={tw`bg-app flex-1`}>
|
||||
<SafeAreaProvider style={tw`flex-1 bg-app`}>
|
||||
<GestureHandlerRootView style={tw`flex-1`}>
|
||||
<MenuProvider>
|
||||
<BottomSheetModalProvider>
|
||||
|
||||
@@ -27,7 +27,10 @@ const CreateLibraryDialog = ({ children, onSubmit, disableBackdropClose }: Props
|
||||
setLibName('');
|
||||
|
||||
// We do this instead of invalidating the query because it triggers a full app re-render??
|
||||
queryClient.setQueryData(['library.list'], (libraries: any) => [...(libraries || []), lib]);
|
||||
queryClient.setQueryData(['library.list'], (libraries: any) => [
|
||||
...(libraries || []),
|
||||
lib
|
||||
]);
|
||||
|
||||
// Switch to the new library
|
||||
currentLibraryStore.id = lib.uuid;
|
||||
|
||||
@@ -24,7 +24,7 @@ const DrawerContent = ({ navigation, state }: DrawerContentComponentProps) => {
|
||||
<View>
|
||||
<View style={tw`flex flex-row items-center`}>
|
||||
<Image source={AppLogo} style={tw`h-[40px] w-[40px]`} />
|
||||
<Text style={tw`text-ink ml-2 text-lg font-bold`}>Spacedrive</Text>
|
||||
<Text style={tw`ml-2 text-lg font-bold text-ink`}>Spacedrive</Text>
|
||||
</View>
|
||||
<View style={tw`mt-6`} />
|
||||
{/* Library Manager */}
|
||||
|
||||
@@ -29,13 +29,15 @@ const DrawerLibraryManager = () => {
|
||||
<Pressable onPress={() => setDropdownClosed((v) => !v)}>
|
||||
<View
|
||||
style={twStyle(
|
||||
'bg-sidebar-box flex h-10 w-full flex-row items-center justify-between border px-3 shadow-sm',
|
||||
'flex h-10 w-full flex-row items-center justify-between border bg-sidebar-box px-3 shadow-sm',
|
||||
dropdownClosed
|
||||
? 'border-sidebar-line/50 rounded-md'
|
||||
: 'border-b-app-box border-sidebar-line bg-sidebar-button rounded-t-md'
|
||||
? 'rounded-md border-sidebar-line/50'
|
||||
: 'rounded-t-md border-sidebar-line border-b-app-box bg-sidebar-button'
|
||||
)}
|
||||
>
|
||||
<Text style={tw`text-ink text-sm font-semibold`}>{currentLibrary?.config.name}</Text>
|
||||
<Text style={tw`text-sm font-semibold text-ink`}>
|
||||
{currentLibrary?.config.name}
|
||||
</Text>
|
||||
<MotiView
|
||||
animate={{
|
||||
rotate: dropdownClosed ? '0deg' : '180deg',
|
||||
@@ -48,21 +50,24 @@ const DrawerLibraryManager = () => {
|
||||
</View>
|
||||
</Pressable>
|
||||
<AnimatedHeight hide={dropdownClosed}>
|
||||
<View style={tw`bg-sidebar-button border-sidebar-line rounded-b-md p-2`}>
|
||||
<View style={tw`rounded-b-md border-sidebar-line bg-sidebar-button p-2`}>
|
||||
{/* Libraries */}
|
||||
{libraries.data?.map((library) => {
|
||||
// console.log('library', library);
|
||||
return (
|
||||
<Pressable key={library.uuid} onPress={() => (currentLibraryStore.id = library.uuid)}>
|
||||
<Pressable
|
||||
key={library.uuid}
|
||||
onPress={() => (currentLibraryStore.id = library.uuid)}
|
||||
>
|
||||
<View
|
||||
style={twStyle(
|
||||
'mt-1 p-2',
|
||||
currentLibrary?.uuid === library.uuid && 'bg-accent rounded'
|
||||
currentLibrary?.uuid === library.uuid && 'rounded bg-accent'
|
||||
)}
|
||||
>
|
||||
<Text
|
||||
style={twStyle(
|
||||
'text-ink text-sm font-semibold',
|
||||
'text-sm font-semibold text-ink',
|
||||
currentLibrary?.uuid === library.uuid && 'text-white'
|
||||
)}
|
||||
>
|
||||
@@ -83,7 +88,9 @@ const DrawerLibraryManager = () => {
|
||||
</CreateLibraryDialog>
|
||||
{/* Manage Library */}
|
||||
<Pressable
|
||||
onPress={() => navigation.navigate('Settings', { screen: 'LibraryGeneralSettings' })}
|
||||
onPress={() =>
|
||||
navigation.navigate('Settings', { screen: 'LibraryGeneralSettings' })
|
||||
}
|
||||
>
|
||||
<View style={tw`flex flex-row items-center px-1.5 py-[8px]`}>
|
||||
<Gear size={18} weight="bold" color="white" style={tw`mr-2`} />
|
||||
|
||||
@@ -63,8 +63,10 @@ const DrawerLocations = ({ stackName }: DrawerLocationsProp) => {
|
||||
</View>
|
||||
{/* Add Location */}
|
||||
<Pressable onPress={() => importModalRef.current?.present()}>
|
||||
<View style={tw`border-app-line/80 mt-1 rounded border border-dashed`}>
|
||||
<Text style={tw`p-2 text-center text-xs font-bold text-gray-400`}>Add Location</Text>
|
||||
<View style={tw`mt-1 rounded border border-dashed border-app-line/80`}>
|
||||
<Text style={tw`p-2 text-center text-xs font-bold text-gray-400`}>
|
||||
Add Location
|
||||
</Text>
|
||||
</View>
|
||||
</Pressable>
|
||||
</CollapsibleView>
|
||||
|
||||
@@ -62,7 +62,7 @@ const DrawerTags = ({ stackName }: DrawerTagsProp) => {
|
||||
</View>
|
||||
{/* Add Tag */}
|
||||
<Pressable onPress={() => createTagModalRef.current?.present()}>
|
||||
<View style={tw`border-app-line/80 mt-1 rounded border border-dashed`}>
|
||||
<View style={tw`mt-1 rounded border border-dashed border-app-line/80`}>
|
||||
<Text style={tw`p-2 text-center text-xs font-bold text-gray-400`}>Add Tag</Text>
|
||||
</View>
|
||||
</Pressable>
|
||||
|
||||
@@ -32,7 +32,10 @@ const Explorer = ({ data }: ExplorerProps) => {
|
||||
|
||||
function handlePress(data: ExplorerItem) {
|
||||
if (isPath(data) && data.item.is_dir) {
|
||||
navigation.push('Location', { id: data.item.location_id, path: data.item.materialized_path });
|
||||
navigation.push('Location', {
|
||||
id: data.item.location_id,
|
||||
path: data.item.materialized_path
|
||||
});
|
||||
} else {
|
||||
setData(data);
|
||||
modalRef.current?.present();
|
||||
@@ -65,7 +68,11 @@ const Explorer = ({ data }: ExplorerProps) => {
|
||||
keyExtractor={(item) => item.item.id.toString()}
|
||||
renderItem={({ item }) => (
|
||||
<Pressable onPress={() => handlePress(item)}>
|
||||
{layoutMode === 'grid' ? <FileItem data={item} /> : <FileRow data={item} />}
|
||||
{layoutMode === 'grid' ? (
|
||||
<FileItem data={item} />
|
||||
) : (
|
||||
<FileRow data={item} />
|
||||
)}
|
||||
</Pressable>
|
||||
)}
|
||||
extraData={layoutMode}
|
||||
|
||||
@@ -20,7 +20,7 @@ const FileRow = ({ data }: FileRowProps) => {
|
||||
>
|
||||
<FileThumb data={data} size={0.6} />
|
||||
<View style={tw`ml-3`}>
|
||||
<Text numberOfLines={1} style={tw`text-ink-dull text-center text-xs font-medium`}>
|
||||
<Text numberOfLines={1} style={tw`text-center text-xs font-medium text-ink-dull`}>
|
||||
{filePath?.name}
|
||||
{filePath?.extension && `.${filePath.extension}`}
|
||||
</Text>
|
||||
|
||||
@@ -27,7 +27,9 @@ const InfoTagPills = ({ data, style }: Props) => {
|
||||
text={isDir ? 'Folder' : ObjectKind[objectData?.kind || 0]!}
|
||||
/>
|
||||
{/* Extension */}
|
||||
{filePath?.extension && <InfoPill text={filePath.extension} containerStyle={tw`mr-1`} />}
|
||||
{filePath?.extension && (
|
||||
<InfoPill text={filePath.extension} containerStyle={tw`mr-1`} />
|
||||
)}
|
||||
{/* TODO: What happens if I have too many? */}
|
||||
{tagsQuery.data?.map((tag) => (
|
||||
<InfoPill
|
||||
|
||||
@@ -4,7 +4,10 @@ import { tw } from '~/lib/tailwind';
|
||||
|
||||
export const Switch: FC<SwitchProps> = ({ ...props }) => {
|
||||
return (
|
||||
<RNSwitch trackColor={{ false: tw.color('app-line'), true: tw.color('accent') }} {...props} />
|
||||
<RNSwitch
|
||||
trackColor={{ false: tw.color('app-line'), true: tw.color('accent') }}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -14,10 +17,13 @@ export const SwitchContainer: FC<SwitchContainerProps> = ({ title, description,
|
||||
return (
|
||||
<View style={tw`flex flex-row items-center justify-between pb-6`}>
|
||||
<View style={tw`w-[80%]`}>
|
||||
<Text style={tw`text-ink text-sm font-medium`}>{title}</Text>
|
||||
{description && <Text style={tw`text-ink-dull mt-2 text-sm`}>{description}</Text>}
|
||||
<Text style={tw`text-sm font-medium text-ink`}>{title}</Text>
|
||||
{description && <Text style={tw`mt-2 text-sm text-ink-dull`}>{description}</Text>}
|
||||
</View>
|
||||
<Switch trackColor={{ false: tw.color('app-line'), true: tw.color('accent') }} {...props} />
|
||||
<Switch
|
||||
trackColor={{ false: tw.color('app-line'), true: tw.color('accent') }}
|
||||
{...props}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -17,7 +17,7 @@ export default function Header() {
|
||||
|
||||
return (
|
||||
<View
|
||||
style={twStyle('border-app-line bg-app-overlay mx-4 rounded border', {
|
||||
style={twStyle('mx-4 rounded border border-app-line bg-app-overlay', {
|
||||
marginTop: top + 10
|
||||
})}
|
||||
>
|
||||
@@ -38,7 +38,7 @@ export default function Header() {
|
||||
style={tw`h-full flex-1 justify-center`}
|
||||
onPress={() => navigation.navigate('Search')}
|
||||
>
|
||||
<Text style={tw`text-ink-dull text-sm font-medium`}>Search</Text>
|
||||
<Text style={tw`text-sm font-medium text-ink-dull`}>Search</Text>
|
||||
</Pressable>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -29,7 +29,7 @@ const PasswordMeter = (props: PasswordMeterProps) => {
|
||||
{scoreText}
|
||||
</Text>
|
||||
</View>
|
||||
<View style={tw`bg-app-box/80 mt-2 w-full rounded-full`}>
|
||||
<View style={tw`mt-2 w-full rounded-full bg-app-box/80`}>
|
||||
<View
|
||||
style={twStyle(
|
||||
{
|
||||
|
||||
@@ -11,7 +11,10 @@ const Card = ({ children, ...props }: CardProps) => {
|
||||
|
||||
return (
|
||||
<View
|
||||
style={twStyle('border-app-line bg-app-overlay rounded-lg border px-4 py-5', style as string)}
|
||||
style={twStyle(
|
||||
'rounded-lg border border-app-line bg-app-overlay px-4 py-5',
|
||||
style as string
|
||||
)}
|
||||
{...otherProps}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -48,7 +48,9 @@ const Dialog = (props: DialogProps) => {
|
||||
<View>
|
||||
{props.trigger && (
|
||||
<Pressable
|
||||
onPress={() => (props.setIsVisible ? props.setIsVisible(true) : setVisible(true))}
|
||||
onPress={() =>
|
||||
props.setIsVisible ? props.setIsVisible(true) : setVisible(true)
|
||||
}
|
||||
>
|
||||
{props.trigger}
|
||||
</Pressable>
|
||||
@@ -56,7 +58,7 @@ const Dialog = (props: DialogProps) => {
|
||||
<Modal renderToHardwareTextureAndroid transparent visible={props.isVisible ?? visible}>
|
||||
{/* Backdrop */}
|
||||
<Pressable
|
||||
style={tw`bg-app-box/40 absolute inset-0`}
|
||||
style={tw`absolute inset-0 bg-app-box/40`}
|
||||
onPress={handleCloseDialog}
|
||||
disabled={props.disableBackdropClose || props.loading}
|
||||
/>
|
||||
@@ -74,14 +76,14 @@ const Dialog = (props: DialogProps) => {
|
||||
>
|
||||
{/* TODO: Blur may look cool here */}
|
||||
<View
|
||||
style={tw`border-app-line bg-app shadow-app-shade min-w-[360px] max-w-[380px] overflow-hidden rounded-md border shadow`}
|
||||
style={tw`min-w-[360px] max-w-[380px] overflow-hidden rounded-md border border-app-line bg-app shadow shadow-app-shade`}
|
||||
>
|
||||
<View style={tw`p-5`}>
|
||||
{/* Title */}
|
||||
<Text style={tw`text-ink text-base font-bold`}>{props.title}</Text>
|
||||
<Text style={tw`text-base font-bold text-ink`}>{props.title}</Text>
|
||||
{/* Description */}
|
||||
{props.description && (
|
||||
<Text style={tw`text-ink-dull mt-2 text-sm leading-normal`}>
|
||||
<Text style={tw`mt-2 text-sm leading-normal text-ink-dull`}>
|
||||
{props.description}
|
||||
</Text>
|
||||
)}
|
||||
@@ -90,7 +92,7 @@ const Dialog = (props: DialogProps) => {
|
||||
</View>
|
||||
{/* Actions */}
|
||||
<View
|
||||
style={tw`border-app-line bg-app-highlight flex flex-row items-center border-t p-3`}
|
||||
style={tw`flex flex-row items-center border-t border-app-line bg-app-highlight p-3`}
|
||||
>
|
||||
{props.loading && <PulseAnimation style={tw`h-7`} />}
|
||||
<View style={tw`grow`} />
|
||||
@@ -99,7 +101,7 @@ const Dialog = (props: DialogProps) => {
|
||||
disabled={props.loading} // Disables Close button if loading
|
||||
onPress={handleCloseDialog}
|
||||
>
|
||||
<Text style={tw`text-ink text-sm`}>Close</Text>
|
||||
<Text style={tw`text-sm text-ink`}>Close</Text>
|
||||
</Button>
|
||||
{props.ctaAction && (
|
||||
<Button
|
||||
@@ -108,7 +110,7 @@ const Dialog = (props: DialogProps) => {
|
||||
onPress={props.ctaAction}
|
||||
disabled={props.ctaDisabled || props.loading}
|
||||
>
|
||||
<Text style={tw`text-ink text-sm`}>{props.ctaLabel}</Text>
|
||||
<Text style={tw`text-sm text-ink`}>{props.ctaLabel}</Text>
|
||||
</Button>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -26,13 +26,13 @@ interface ModalHandle extends BottomSheetHandleProps {
|
||||
const ModalHandle = (props: ModalHandle) => (
|
||||
<BottomSheetHandle
|
||||
{...props}
|
||||
style={tw`bg-app items-end rounded-t-2xl`}
|
||||
style={tw`items-end rounded-t-2xl bg-app`}
|
||||
indicatorStyle={tw`bg-app-highlight/60`}
|
||||
>
|
||||
{props.showCloseButton && (
|
||||
<Pressable
|
||||
onPress={() => props.modalRef.current?.close()}
|
||||
style={tw`bg-app-button absolute top-5 right-4 h-7 w-7 items-center justify-center rounded-full`}
|
||||
style={tw`absolute top-5 right-4 h-7 w-7 items-center justify-center rounded-full bg-app-button`}
|
||||
>
|
||||
<X size={16} color="white" weight="bold" />
|
||||
</Pressable>
|
||||
@@ -61,7 +61,7 @@ export const Modal = forwardRef<ModalRef, ModalProps>((props, ref) => {
|
||||
handleComponent={(props) => ModalHandle({ modalRef, showCloseButton, ...props })}
|
||||
{...otherProps}
|
||||
>
|
||||
{title && <Text style={tw`text-ink text-center text-base font-medium`}>{title}</Text>}
|
||||
{title && <Text style={tw`text-center text-base font-medium text-ink`}>{title}</Text>}
|
||||
{children}
|
||||
</BottomSheetModal>
|
||||
);
|
||||
@@ -107,16 +107,22 @@ export const ConfirmModal = forwardRef<ModalRef, ConfirmModalProps>((props, ref)
|
||||
ref={modalRef}
|
||||
backgroundStyle={tw`bg-app`}
|
||||
backdropComponent={ModalBackdrop}
|
||||
handleComponent={(props) => ModalHandle({ modalRef, showCloseButton: false, ...props })}
|
||||
handleComponent={(props) =>
|
||||
ModalHandle({ modalRef, showCloseButton: false, ...props })
|
||||
}
|
||||
snapPoints={props.snapPoints ?? ['25%']}
|
||||
>
|
||||
{/* Title */}
|
||||
{props.title && (
|
||||
<Text style={tw`text-ink text-center text-base font-medium`}>{props.title}</Text>
|
||||
<Text style={tw`text-center text-base font-medium text-ink`}>
|
||||
{props.title}
|
||||
</Text>
|
||||
)}
|
||||
<View style={tw`mt-4 px-6`}>
|
||||
{/* Description */}
|
||||
{props.description && <Text style={tw`text-ink-dull text-sm`}>{props.description}</Text>}
|
||||
{props.description && (
|
||||
<Text style={tw`text-sm text-ink-dull`}>{props.description}</Text>
|
||||
)}
|
||||
{/* Children */}
|
||||
{props.children && props.children}
|
||||
{/* Buttons */}
|
||||
@@ -128,7 +134,7 @@ export const ConfirmModal = forwardRef<ModalRef, ConfirmModalProps>((props, ref)
|
||||
disabled={props.loading} // Disables Close button if loading
|
||||
onPress={() => modalRef.current?.close()}
|
||||
>
|
||||
<Text style={tw`text-ink text-sm font-medium`}>Close</Text>
|
||||
<Text style={tw`text-sm font-medium text-ink`}>Close</Text>
|
||||
</Button>
|
||||
{props.ctaAction && (
|
||||
<Button
|
||||
@@ -138,7 +144,9 @@ export const ConfirmModal = forwardRef<ModalRef, ConfirmModalProps>((props, ref)
|
||||
onPress={props.ctaAction}
|
||||
disabled={props.ctaDisabled || props.loading}
|
||||
>
|
||||
<Text style={tw`text-ink text-sm font-medium`}>{props.ctaLabel}</Text>
|
||||
<Text style={tw`text-sm font-medium text-ink`}>
|
||||
{props.ctaLabel}
|
||||
</Text>
|
||||
</Button>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -26,7 +26,7 @@ const SortByMenu = () => {
|
||||
<Menu
|
||||
trigger={
|
||||
<View style={tw`flex flex-row items-center`}>
|
||||
<Text style={tw`text-ink mr-0.5 font-medium`}>{sortOptions[sortBy]}</Text>
|
||||
<Text style={tw`mr-0.5 font-medium text-ink`}>{sortOptions[sortBy]}</Text>
|
||||
{sortDirection === 'asc' ? <ArrowUpIcon /> : <ArrowDownIcon />}
|
||||
</View>
|
||||
}
|
||||
@@ -35,7 +35,11 @@ const SortByMenu = () => {
|
||||
<MenuItem
|
||||
key={value}
|
||||
icon={
|
||||
value === sortBy ? (sortDirection === 'asc' ? ArrowUpIcon : ArrowDownIcon) : undefined
|
||||
value === sortBy
|
||||
? sortDirection === 'asc'
|
||||
? ArrowUpIcon
|
||||
: ArrowDownIcon
|
||||
: undefined
|
||||
}
|
||||
text={text}
|
||||
value={value}
|
||||
|
||||
@@ -26,7 +26,7 @@ type ActionsContainerProps = PropsWithChildren<{
|
||||
}>;
|
||||
|
||||
const ActionsContainer = ({ children, style }: ActionsContainerProps) => (
|
||||
<View style={twStyle('bg-app-box rounded-lg py-3.5', style)}>{children}</View>
|
||||
<View style={twStyle('rounded-lg bg-app-box py-3.5', style)}>{children}</View>
|
||||
);
|
||||
|
||||
type ActionsItemProps = {
|
||||
@@ -53,7 +53,7 @@ const ActionsItem = ({ icon, onPress, title, isDanger = false }: ActionsItemProp
|
||||
);
|
||||
};
|
||||
|
||||
const ActionDivider = () => <View style={tw`bg-app-line/80 my-3.5 h-[0.5px]`} />;
|
||||
const ActionDivider = () => <View style={tw`my-3.5 h-[0.5px] bg-app-line/80`} />;
|
||||
|
||||
export const ActionsModal = () => {
|
||||
const fileInfoRef = useRef<ModalRef>(null);
|
||||
@@ -75,15 +75,18 @@ export const ActionsModal = () => {
|
||||
</Pressable>
|
||||
<View style={tw`ml-2 flex-1`}>
|
||||
{/* Name + Extension */}
|
||||
<Text style={tw`text-base font-bold text-gray-200`} numberOfLines={1}>
|
||||
<Text
|
||||
style={tw`text-base font-bold text-gray-200`}
|
||||
numberOfLines={1}
|
||||
>
|
||||
{filePath?.name}
|
||||
{filePath?.extension && `.${filePath?.extension}`}
|
||||
</Text>
|
||||
<View style={tw`flex flex-row`}>
|
||||
<Text style={tw`text-ink-faint text-xs`}>
|
||||
<Text style={tw`text-xs text-ink-faint`}>
|
||||
{formatBytes(Number(filePath?.size_in_bytes || 0))},
|
||||
</Text>
|
||||
<Text style={tw`text-ink-faint text-xs`}>
|
||||
<Text style={tw`text-xs text-ink-faint`}>
|
||||
{' '}
|
||||
{dayjs(filePath?.date_created).format('MMM Do YYYY')}
|
||||
</Text>
|
||||
|
||||
@@ -69,13 +69,18 @@ const FileInfoModal = forwardRef<ModalRef, FileInfoModalProps>((props, ref) => {
|
||||
{data && (
|
||||
<ModalScrollView style={tw`flex-1 p-4`}>
|
||||
{/* Back Button */}
|
||||
<Pressable onPress={() => modalRef.current?.close()} style={tw`absolute z-10 ml-4`}>
|
||||
<Pressable
|
||||
onPress={() => modalRef.current?.close()}
|
||||
style={tw`absolute z-10 ml-4`}
|
||||
>
|
||||
<CaretLeft color={tw.color('accent')} size={20} weight="bold" />
|
||||
</Pressable>
|
||||
{/* File Icon / Name */}
|
||||
<View style={tw`items-center`}>
|
||||
<FileThumb data={data} size={1.6} />
|
||||
<Text style={tw`mt-2 text-base font-bold text-gray-200`}>{filePathData?.name}</Text>
|
||||
<Text style={tw`mt-2 text-base font-bold text-gray-200`}>
|
||||
{filePathData?.name}
|
||||
</Text>
|
||||
<InfoTagPills data={data} style={tw`mt-3`} />
|
||||
</View>
|
||||
{/* Details */}
|
||||
@@ -112,7 +117,11 @@ const FileInfoModal = forwardRef<ModalRef, FileInfoModalProps>((props, ref) => {
|
||||
<>
|
||||
{/* TODO: Note */}
|
||||
{filePathData.cas_id && (
|
||||
<MetaItem icon={Snowflake} title="Content ID" value={filePathData.cas_id} />
|
||||
<MetaItem
|
||||
icon={Snowflake}
|
||||
title="Content ID"
|
||||
value={filePathData.cas_id}
|
||||
/>
|
||||
)}
|
||||
{/* Checksum */}
|
||||
{filePathData?.integrity_checksum && (
|
||||
|
||||
@@ -76,7 +76,10 @@ const CreateTagModal = forwardRef<ModalRef, unknown>((_, ref) => {
|
||||
{showPicker && (
|
||||
<FadeInAnimation>
|
||||
<View style={tw`mt-4 h-64`}>
|
||||
<ColorPicker color={tagColor} onColorChangeComplete={(color) => setTagColor(color)} />
|
||||
<ColorPicker
|
||||
color={tagColor}
|
||||
onColorChangeComplete={(color) => setTagColor(color)}
|
||||
/>
|
||||
</View>
|
||||
</FadeInAnimation>
|
||||
)}
|
||||
|
||||
@@ -56,9 +56,9 @@ const UpdateTagModal = forwardRef<ModalRef, Props>((props, ref) => {
|
||||
showCloseButton
|
||||
>
|
||||
<View style={tw`p-4`}>
|
||||
<Text style={tw`text-ink-dull mb-1 ml-1 text-xs font-medium`}>Name</Text>
|
||||
<Text style={tw`mb-1 ml-1 text-xs font-medium text-ink-dull`}>Name</Text>
|
||||
<Input value={tagName} onChangeText={(t) => setTagName(t)} />
|
||||
<Text style={tw`text-ink-dull mb-1 ml-1 mt-3 text-xs font-medium`}>Color</Text>
|
||||
<Text style={tw`mb-1 ml-1 mt-3 text-xs font-medium text-ink-dull`}>Color</Text>
|
||||
<View style={tw`ml-2 flex flex-row items-center`}>
|
||||
<Pressable
|
||||
onPress={() => setShowPicker((v) => !v)}
|
||||
@@ -70,7 +70,10 @@ const UpdateTagModal = forwardRef<ModalRef, Props>((props, ref) => {
|
||||
{showPicker && (
|
||||
<FadeInAnimation>
|
||||
<View style={tw`mt-4 h-64`}>
|
||||
<ColorPicker color={tagColor} onColorChangeComplete={(color) => setTagColor(color)} />
|
||||
<ColorPicker
|
||||
color={tagColor}
|
||||
onColorChangeComplete={(color) => setTagColor(color)}
|
||||
/>
|
||||
</View>
|
||||
</FadeInAnimation>
|
||||
)}
|
||||
|
||||
@@ -34,7 +34,9 @@ const OverviewStats = () => {
|
||||
|
||||
const { data: libraryStatistics } = useLibraryQuery(['library.getStatistics']);
|
||||
|
||||
const displayableStatItems = Object.keys(StatItemNames) as unknown as keyof typeof StatItemNames;
|
||||
const displayableStatItems = Object.keys(
|
||||
StatItemNames
|
||||
) as unknown as keyof typeof StatItemNames;
|
||||
|
||||
// For Demo purposes as we probably wanna save this to database
|
||||
// Sets Total Capacity and Free Space of the device
|
||||
@@ -59,7 +61,13 @@ const OverviewStats = () => {
|
||||
} else if (key === 'total_bytes_capacity') {
|
||||
bytes = BigInt(sizeInfo.totalSpace);
|
||||
}
|
||||
return <StatItem key={key} title={StatItemNames[key as keyof Statistics]!} bytes={bytes} />;
|
||||
return (
|
||||
<StatItem
|
||||
key={key}
|
||||
title={StatItemNames[key as keyof Statistics]!}
|
||||
bytes={bytes}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</ScrollView>
|
||||
) : (
|
||||
|
||||
@@ -10,7 +10,7 @@ const button = cva(['items-center justify-center rounded-md border shadow-sm'],
|
||||
danger: ['border-red-800 bg-red-600'],
|
||||
gray: ['border-app-line bg-app-button'],
|
||||
darkGray: ['border-app-box bg-app'],
|
||||
accent: ['border-accent-deep bg-accent shadow-app-shade/10 shadow-md'],
|
||||
accent: ['border-accent-deep bg-accent shadow-md shadow-app-shade/10'],
|
||||
outline: ['border-sidebar-line/60 ']
|
||||
},
|
||||
size: {
|
||||
|
||||
@@ -12,11 +12,11 @@ export const InfoPill = (props: Props) => {
|
||||
return (
|
||||
<View
|
||||
style={twStyle(
|
||||
'shadow-app-shade/5 bg-app-highlight rounded-md border border-transparent px-[6px] py-[1px] shadow',
|
||||
'rounded-md border border-transparent bg-app-highlight px-[6px] py-[1px] shadow shadow-app-shade/5',
|
||||
props.containerStyle
|
||||
)}
|
||||
>
|
||||
<Text style={twStyle('text-ink-dull text-xs font-medium', props.textStyle)}>
|
||||
<Text style={twStyle('text-xs font-medium text-ink-dull', props.textStyle)}>
|
||||
{props.text}
|
||||
</Text>
|
||||
</View>
|
||||
@@ -27,11 +27,11 @@ export function PlaceholderPill(props: Props) {
|
||||
return (
|
||||
<View
|
||||
style={twStyle(
|
||||
'shadow-app-shade/10 border-app-highlight rounded-md border border-dashed bg-transparent px-[6px] py-[1px] shadow',
|
||||
'rounded-md border border-dashed border-app-highlight bg-transparent px-[6px] py-[1px] shadow shadow-app-shade/10',
|
||||
props.containerStyle
|
||||
)}
|
||||
>
|
||||
<Text style={twStyle('text-ink-faint/70 text-xs font-medium', props.textStyle)}>
|
||||
<Text style={twStyle('text-xs font-medium text-ink-faint/70', props.textStyle)}>
|
||||
{props.text}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
@@ -20,7 +20,7 @@ export const Menu = (props: MenuProps) => (
|
||||
<View>
|
||||
<PMenu renderer={renderers.NotAnimatedContextMenu}>
|
||||
<MenuTrigger>{props.trigger}</MenuTrigger>
|
||||
<MenuOptions optionsContainerStyle={tw`bg-app-menu rounded p-1`}>
|
||||
<MenuOptions optionsContainerStyle={tw`rounded bg-app-menu p-1`}>
|
||||
{props.children}
|
||||
</MenuOptions>
|
||||
</PMenu>
|
||||
@@ -44,7 +44,7 @@ export const MenuItem = ({ icon, ...props }: MenuItemProps) => {
|
||||
<MenuOption
|
||||
{...props}
|
||||
customStyles={{
|
||||
optionText: tw`text-ink py-0.5 text-sm font-medium`
|
||||
optionText: tw`py-0.5 text-sm font-medium text-ink`
|
||||
}}
|
||||
style={tw`flex flex-row items-center`}
|
||||
/>
|
||||
|
||||
@@ -10,9 +10,11 @@ type SettingsContainerProps = PropsWithChildren<{
|
||||
export function SettingsContainer({ children, title, description }: SettingsContainerProps) {
|
||||
return (
|
||||
<View>
|
||||
{title && <Text style={tw`text-ink-dull pb-2 pl-3 text-sm font-semibold`}>{title}</Text>}
|
||||
{title && (
|
||||
<Text style={tw`pb-2 pl-3 text-sm font-semibold text-ink-dull`}>{title}</Text>
|
||||
)}
|
||||
{children}
|
||||
{description && <Text style={tw`text-ink-dull px-3 pt-2 text-sm`}>{description}</Text>}
|
||||
{description && <Text style={tw`px-3 pt-2 text-sm text-ink-dull`}>{description}</Text>}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,12 +12,17 @@ type SettingsItemProps = {
|
||||
export function SettingsItem(props: SettingsItemProps) {
|
||||
return (
|
||||
<Pressable onPress={props.onPress}>
|
||||
<View style={tw`bg-app-box flex flex-row items-center justify-between px-4`}>
|
||||
<View style={tw`flex flex-row items-center justify-between bg-app-box px-4`}>
|
||||
<View style={tw`flex flex-row items-center py-4`}>
|
||||
{props.leftIcon && props.leftIcon({ size: 20, color: tw.color('ink'), style: tw`mr-3` })}
|
||||
<Text style={tw`text-ink text-[14px]`}>{props.title}</Text>
|
||||
{props.leftIcon &&
|
||||
props.leftIcon({ size: 20, color: tw.color('ink'), style: tw`mr-3` })}
|
||||
<Text style={tw`text-[14px] text-ink`}>{props.title}</Text>
|
||||
</View>
|
||||
{props.rightArea ? props.rightArea : <CaretRight size={20} color={tw.color('ink-dull')} />}
|
||||
{props.rightArea ? (
|
||||
props.rightArea
|
||||
) : (
|
||||
<CaretRight size={20} color={tw.color('ink-dull')} />
|
||||
)}
|
||||
</View>
|
||||
</Pressable>
|
||||
);
|
||||
@@ -26,7 +31,7 @@ export function SettingsItem(props: SettingsItemProps) {
|
||||
export function SettingsItemDivider() {
|
||||
return (
|
||||
<View style={tw`bg-app-overlay`}>
|
||||
<View style={tw`border-b-app-line mx-3 border-b`} />
|
||||
<View style={tw`mx-3 border-b border-b-app-line`} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -40,9 +40,9 @@ globalThis.localStorage = {
|
||||
length: _localStorage.size
|
||||
};
|
||||
|
||||
/*
|
||||
/*
|
||||
https://github.com/facebook/hermes/issues/23
|
||||
|
||||
|
||||
We are using "Hermes" on Android & IOS, which for the current version (0.11),
|
||||
IOS does not support the Intl fully so we need polyfill it.
|
||||
|
||||
|
||||
@@ -13,7 +13,11 @@ const Stack = createStackNavigator<RootStackParamList>();
|
||||
export default function RootNavigator() {
|
||||
return (
|
||||
<Stack.Navigator initialRouteName="Root">
|
||||
<Stack.Screen name="Root" component={DrawerNavigator} options={{ headerShown: false }} />
|
||||
<Stack.Screen
|
||||
name="Root"
|
||||
component={DrawerNavigator}
|
||||
options={{ headerShown: false }}
|
||||
/>
|
||||
<Stack.Screen name="NotFound" component={NotFoundScreen} options={{ title: 'Oops!' }} />
|
||||
<Stack.Screen
|
||||
name="Search"
|
||||
|
||||
@@ -19,7 +19,11 @@ export default function SpacedropStack() {
|
||||
headerBackTitleStyle: tw`text-base`
|
||||
}}
|
||||
>
|
||||
<Stack.Screen name="Spacedrop" component={SpacedropScreen} options={{ header: Header }} />
|
||||
<Stack.Screen
|
||||
name="Spacedrop"
|
||||
component={SpacedropScreen}
|
||||
options={{ header: Header }}
|
||||
/>
|
||||
{SharedScreens(Stack as any)}
|
||||
</Stack.Navigator>
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function NotFoundScreen({ navigation }: RootStackScreenProps<'Not
|
||||
}
|
||||
style={tw`mt-4 py-4`}
|
||||
>
|
||||
<Text style={tw`text-ink-dull text-sm`}>Go to home screen!</Text>
|
||||
<Text style={tw`text-sm text-ink-dull`}>Go to home screen!</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -18,13 +18,17 @@ const SearchScreen = ({ navigation }: RootStackScreenProps<'Search'>) => {
|
||||
{/* Header */}
|
||||
<View style={tw`mx-4 flex flex-row items-center`}>
|
||||
{/* Search Input */}
|
||||
<View style={tw`border-app-line bg-app-overlay mr-3 h-10 flex-1 rounded border`}>
|
||||
<View style={tw`mr-3 h-10 flex-1 rounded border border-app-line bg-app-overlay`}>
|
||||
<View style={tw`flex h-full flex-row items-center px-3`}>
|
||||
<View style={tw`mr-3`}>
|
||||
{loading ? (
|
||||
<ActivityIndicator size={'small'} color={'white'} />
|
||||
) : (
|
||||
<MagnifyingGlass size={20} weight="light" color={tw.color('ink-faint')} />
|
||||
<MagnifyingGlass
|
||||
size={20}
|
||||
weight="light"
|
||||
color={tw.color('ink-faint')}
|
||||
/>
|
||||
)}
|
||||
</View>
|
||||
<TextInput
|
||||
@@ -32,7 +36,7 @@ const SearchScreen = ({ navigation }: RootStackScreenProps<'Search'>) => {
|
||||
clearButtonMode="never" // can't change the color??
|
||||
underlineColorAndroid="transparent"
|
||||
placeholderTextColor={tw.color('ink-dull')}
|
||||
style={tw`text-ink flex-1 text-sm font-medium`}
|
||||
style={tw`flex-1 text-sm font-medium text-ink`}
|
||||
textContentType={'none'}
|
||||
autoFocus
|
||||
autoCapitalize="none"
|
||||
|
||||
@@ -50,7 +50,10 @@ const Hexagon = () => {
|
||||
|
||||
return (
|
||||
<Svg width={width} height={height} viewBox="0 0 100 100">
|
||||
<Polygon points="0,25 0,75 50,100 100,75 100,25 50,0" fill={tw.color('bg-app-box/30')} />
|
||||
<Polygon
|
||||
points="0,25 0,75 50,100 100,75 100,25 50,0"
|
||||
fill={tw.color('bg-app-box/30')}
|
||||
/>
|
||||
</Svg>
|
||||
);
|
||||
};
|
||||
@@ -100,7 +103,9 @@ function DropItem(props: DropItemProps) {
|
||||
style={tw`w-full items-center justify-center`}
|
||||
onPress={() => Alert.alert('TODO')}
|
||||
>
|
||||
<View style={tw`bg-app-button h-12 w-12 items-center justify-center rounded-full`}>
|
||||
<View
|
||||
style={tw`h-12 w-12 items-center justify-center rounded-full bg-app-button`}
|
||||
>
|
||||
{icon}
|
||||
</View>
|
||||
{props.name && (
|
||||
|
||||
@@ -5,7 +5,7 @@ import { SpacesStackScreenProps } from '~/navigation/tabs/SpacesStack';
|
||||
export default function SpacesScreen({ navigation }: SpacesStackScreenProps<'Spaces'>) {
|
||||
return (
|
||||
<View style={tw`flex-1 items-center justify-center`}>
|
||||
<Text style={tw`text-ink text-xl font-bold`}>Spaces</Text>
|
||||
<Text style={tw`text-xl font-bold text-ink`}>Spaces</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -29,7 +29,10 @@ const CreatingLibraryScreen = ({ navigation }: OnboardingStackScreenProps<'Creat
|
||||
const createLibrary = useBridgeMutation('library.create', {
|
||||
onSuccess: (lib) => {
|
||||
resetOnboardingStore();
|
||||
queryClient.setQueryData(['library.list'], (libraries: any) => [...(libraries || []), lib]);
|
||||
queryClient.setQueryData(['library.list'], (libraries: any) => [
|
||||
...(libraries || []),
|
||||
lib
|
||||
]);
|
||||
// Switch to the new library
|
||||
currentLibraryStore.id = lib.uuid;
|
||||
if (obStore.shareTelemetry) {
|
||||
|
||||
@@ -32,7 +32,7 @@ export function OnboardingContainer({ children }: React.PropsWithChildren) {
|
||||
>
|
||||
{children}
|
||||
</KeyboardAvoidingView>
|
||||
<Text style={tw`text-ink-dull/50 absolute bottom-8 text-xs`}>
|
||||
<Text style={tw`absolute bottom-8 text-xs text-ink-dull/50`}>
|
||||
© 2022 Spacedrive Technology Inc.
|
||||
</Text>
|
||||
</View>
|
||||
@@ -72,7 +72,7 @@ const GetStartedScreen = ({ navigation }: OnboardingStackScreenProps<'GetStarted
|
||||
{/* Get Started Button */}
|
||||
<FadeInUpAnimation delay={1200} style={tw`mt-8`}>
|
||||
<AnimatedButton variant="accent" onPress={() => navigation.push('NewLibrary')}>
|
||||
<Text style={tw`text-ink text-center text-base font-medium`}>Get Started</Text>
|
||||
<Text style={tw`text-center text-base font-medium text-ink`}>Get Started</Text>
|
||||
</AnimatedButton>
|
||||
</FadeInUpAnimation>
|
||||
</OnboardingContainer>
|
||||
|
||||
@@ -120,7 +120,7 @@ const MasterPasswordScreen = ({ navigation }: OnboardingStackScreenProps<'Master
|
||||
disabled={form.formState.isSubmitting}
|
||||
onPress={handleSetPassword}
|
||||
>
|
||||
<Text style={tw`text-ink text-center font-medium`}>
|
||||
<Text style={tw`text-center font-medium text-ink`}>
|
||||
{!showPasswordValidate ? 'Set password' : 'Confirm Password'}
|
||||
</Text>
|
||||
</Button>
|
||||
@@ -136,7 +136,9 @@ const MasterPasswordScreen = ({ navigation }: OnboardingStackScreenProps<'Master
|
||||
form.reset();
|
||||
}}
|
||||
>
|
||||
<Text style={tw`text-ink text-center font-medium`}>Remove password</Text>
|
||||
<Text style={tw`text-center font-medium text-ink`}>
|
||||
Remove password
|
||||
</Text>
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
@@ -145,7 +147,9 @@ const MasterPasswordScreen = ({ navigation }: OnboardingStackScreenProps<'Master
|
||||
disabled={form.formState.isSubmitting}
|
||||
onPress={handleNoPassword}
|
||||
>
|
||||
<Text style={tw`text-ink text-center font-medium`}>Continue without password</Text>
|
||||
<Text style={tw`text-center font-medium text-ink`}>
|
||||
Continue without password
|
||||
</Text>
|
||||
</Button>
|
||||
)}
|
||||
</View>
|
||||
|
||||
@@ -38,8 +38,8 @@ const NewLibraryScreen = ({ navigation }: OnboardingStackScreenProps<'NewLibrary
|
||||
<OnboardingTitle style={tw`mt-4`}>Create a Library</OnboardingTitle>
|
||||
<View style={tw`w-full px-4`}>
|
||||
<OnboardingDescription style={tw`mt-4`}>
|
||||
Libraries are a secure, on-device database. Your files remain where they are, the Library
|
||||
catalogs them and stores all Spacedrive related data.
|
||||
Libraries are a secure, on-device database. Your files remain where they are,
|
||||
the Library catalogs them and stores all Spacedrive related data.
|
||||
</OnboardingDescription>
|
||||
<Controller
|
||||
name="name"
|
||||
@@ -64,11 +64,11 @@ const NewLibraryScreen = ({ navigation }: OnboardingStackScreenProps<'NewLibrary
|
||||
)}
|
||||
<View style={tw`mt-4 flex w-full flex-row items-center justify-center`}>
|
||||
<Button variant="accent" onPress={handleNewLibrary}>
|
||||
<Text style={tw`text-ink text-center font-medium`}>New Library</Text>
|
||||
<Text style={tw`text-center font-medium text-ink`}>New Library</Text>
|
||||
</Button>
|
||||
<Text style={tw`text-ink-faint px-4 text-xs font-bold`}>OR</Text>
|
||||
<Text style={tw`px-4 text-xs font-bold text-ink-faint`}>OR</Text>
|
||||
<Button onPress={handleImport} variant="outline">
|
||||
<Text style={tw`text-ink text-center font-medium`}>Import Library</Text>
|
||||
<Text style={tw`text-center font-medium text-ink`}>Import Library</Text>
|
||||
</Button>
|
||||
</View>
|
||||
</OnboardingContainer>
|
||||
|
||||
@@ -18,7 +18,7 @@ const RadioButton = ({ title, description, isSelected, style }: RadioButtonProps
|
||||
return (
|
||||
<View
|
||||
style={twStyle(
|
||||
'border-app-line bg-app-box/50 flex w-full flex-row items-center rounded-md border p-3',
|
||||
'flex w-full flex-row items-center rounded-md border border-app-line bg-app-box/50 p-3',
|
||||
style
|
||||
)}
|
||||
>
|
||||
@@ -31,8 +31,8 @@ const RadioButton = ({ title, description, isSelected, style }: RadioButtonProps
|
||||
{isSelected && <View style={tw`h-1.5 w-1.5 rounded-full bg-white`} />}
|
||||
</View>
|
||||
<View style={tw`flex-1`}>
|
||||
<Text style={tw`text-ink text-base font-bold`}>{title}</Text>
|
||||
<Text style={tw`text-ink-faint text-sm`}>{description}</Text>
|
||||
<Text style={tw`text-base font-bold text-ink`}>{title}</Text>
|
||||
<Text style={tw`text-sm text-ink-faint`}>{description}</Text>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
@@ -52,8 +52,8 @@ const PrivacyScreen = ({ navigation }: OnboardingStackScreenProps<'Privacy'>) =>
|
||||
<OnboardingContainer>
|
||||
<OnboardingTitle>Your Privacy</OnboardingTitle>
|
||||
<OnboardingDescription style={tw`mt-4`}>
|
||||
Spacedrive is built for privacy, that's why we're open source and local first. So we'll make
|
||||
it very clear what data is shared with us.
|
||||
Spacedrive is built for privacy, that's why we're open source and local first. So
|
||||
we'll make it very clear what data is shared with us.
|
||||
</OnboardingDescription>
|
||||
<View style={tw`w-full`}>
|
||||
<Pressable onPress={() => setShareTelemetry('share-telemetry')}>
|
||||
@@ -73,7 +73,7 @@ const PrivacyScreen = ({ navigation }: OnboardingStackScreenProps<'Privacy'>) =>
|
||||
</Pressable>
|
||||
</View>
|
||||
<Button variant="accent" size="sm" onPress={onPress} style={tw`mt-6`}>
|
||||
<Text style={tw`text-ink text-center text-base font-medium`}>Continue</Text>
|
||||
<Text style={tw`text-center text-base font-medium text-ink`}>Continue</Text>
|
||||
</Button>
|
||||
</OnboardingContainer>
|
||||
);
|
||||
|
||||
@@ -109,7 +109,7 @@ function renderSectionHeader({ section }: { section: { title: string } }) {
|
||||
return (
|
||||
<Text
|
||||
style={twStyle(
|
||||
'text-ink mb-2 ml-2 text-sm font-bold',
|
||||
'mb-2 ml-2 text-sm font-bold text-ink',
|
||||
section.title === 'Client' ? 'mt-2' : 'mt-5'
|
||||
)}
|
||||
>
|
||||
@@ -135,9 +135,9 @@ export default function SettingsScreen({ navigation }: SettingsStackScreenProps<
|
||||
renderSectionHeader={renderSectionHeader}
|
||||
ListFooterComponent={
|
||||
<View style={tw`mt-6 mb-4 items-center`}>
|
||||
<Text style={tw`text-ink text-base font-bold`}>Spacedrive</Text>
|
||||
<Text style={tw`text-base font-bold text-ink`}>Spacedrive</Text>
|
||||
{/* TODO: Get this automatically (expo-device have this?) */}
|
||||
<Text style={tw`text-ink-faint mt-0.5 text-xs font-medium`}>v0.1.0</Text>
|
||||
<Text style={tw`mt-0.5 text-xs font-medium text-ink-faint`}>v0.1.0</Text>
|
||||
</View>
|
||||
}
|
||||
showsVerticalScrollIndicator={false}
|
||||
|
||||
@@ -17,15 +17,15 @@ const GeneralSettingsScreen = ({ navigation }: SettingsStackScreenProps<'General
|
||||
<Card style={tw`bg-app-box`}>
|
||||
{/* Card Header */}
|
||||
<View style={tw`flex flex-row justify-between`}>
|
||||
<Text style={tw`text-ink font-semibold`}>Connected Node</Text>
|
||||
<Text style={tw`font-semibold text-ink`}>Connected Node</Text>
|
||||
<View style={tw`flex flex-row`}>
|
||||
{/* Peers */}
|
||||
<View style={tw`bg-app-highlight mr-2 self-start rounded px-1.5 py-[2px]`}>
|
||||
<Text style={tw`text-ink text-xs font-semibold`}>0 Peers</Text>
|
||||
<View style={tw`mr-2 self-start rounded bg-app-highlight px-1.5 py-[2px]`}>
|
||||
<Text style={tw`text-xs font-semibold text-ink`}>0 Peers</Text>
|
||||
</View>
|
||||
{/* Status */}
|
||||
<View style={tw`bg-accent rounded px-1.5 py-[2px]`}>
|
||||
<Text style={tw`text-ink text-xs font-semibold`}>Running</Text>
|
||||
<View style={tw`rounded bg-accent px-1.5 py-[2px]`}>
|
||||
<Text style={tw`text-xs font-semibold text-ink`}>Running</Text>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -50,15 +50,15 @@ function LibraryItem({
|
||||
<Swipeable
|
||||
containerStyle={twStyle(
|
||||
index !== 0 && 'mt-2',
|
||||
'border-app-line bg-app-overlay rounded-lg border px-4 py-3'
|
||||
'rounded-lg border border-app-line bg-app-overlay px-4 py-3'
|
||||
)}
|
||||
enableTrackpadTwoFingerGesture
|
||||
renderRightActions={renderRightActions}
|
||||
>
|
||||
<View style={tw`flex flex-row items-center justify-between`}>
|
||||
<View>
|
||||
<Text style={tw`text-ink font-semibold`}>{library.config.name}</Text>
|
||||
<Text style={tw`text-ink-dull mt-0.5 text-xs`}>{library.uuid}</Text>
|
||||
<Text style={tw`font-semibold text-ink`}>{library.config.name}</Text>
|
||||
<Text style={tw`mt-0.5 text-xs text-ink-dull`}>{library.uuid}</Text>
|
||||
</View>
|
||||
<CaretRight color={tw.color('ink-dull')} size={18} />
|
||||
</View>
|
||||
|
||||
@@ -110,8 +110,8 @@ const EditLocationSettingsScreen = ({
|
||||
)}
|
||||
/>
|
||||
<SettingsInputInfo>
|
||||
The name of this Location, this is what will be displayed in the sidebar. Will not rename
|
||||
the actual folder on disk.
|
||||
The name of this Location, this is what will be displayed in the sidebar. Will
|
||||
not rename the actual folder on disk.
|
||||
</SettingsInputInfo>
|
||||
|
||||
<SettingsInputTitle style={tw`mt-3`}>Local Path</SettingsInputTitle>
|
||||
|
||||
@@ -48,7 +48,7 @@ function LocationItem({ location, index, navigation }: LocationItemProps) {
|
||||
]}
|
||||
>
|
||||
<Pressable
|
||||
style={tw`border-app-line bg-app-button items-center justify-center rounded-md border py-1.5 px-3 shadow-sm`}
|
||||
style={tw`items-center justify-center rounded-md border border-app-line bg-app-button py-1.5 px-3 shadow-sm`}
|
||||
onPress={() => {
|
||||
navigation.navigate('EditLocationSettings', { id: location.id });
|
||||
swipeable.close();
|
||||
@@ -60,7 +60,7 @@ function LocationItem({ location, index, navigation }: LocationItemProps) {
|
||||
locationId={location.id}
|
||||
trigger={
|
||||
<View
|
||||
style={tw`bg-app-button border-app-line items-center justify-center rounded-md border py-1.5 px-3 shadow-sm`}
|
||||
style={tw`items-center justify-center rounded-md border border-app-line bg-app-button py-1.5 px-3 shadow-sm`}
|
||||
>
|
||||
<Trash size={18} color="white" />
|
||||
</View>
|
||||
@@ -68,7 +68,7 @@ function LocationItem({ location, index, navigation }: LocationItemProps) {
|
||||
/>
|
||||
{/* Full Re-scan IS too much here */}
|
||||
<Pressable
|
||||
style={tw`border-app-line bg-app-button items-center justify-center rounded-md border py-1.5 px-3 shadow-sm`}
|
||||
style={tw`items-center justify-center rounded-md border border-app-line bg-app-button py-1.5 px-3 shadow-sm`}
|
||||
onPress={() => fullRescan.mutate(location.id)}
|
||||
>
|
||||
<Repeat size={18} color="white" />
|
||||
@@ -80,7 +80,7 @@ function LocationItem({ location, index, navigation }: LocationItemProps) {
|
||||
return (
|
||||
<Swipeable
|
||||
containerStyle={twStyle(
|
||||
'border-app-line bg-app-overlay rounded-lg border px-4 py-3',
|
||||
'rounded-lg border border-app-line bg-app-overlay px-4 py-3',
|
||||
index !== 0 && 'mt-2'
|
||||
)}
|
||||
enableTrackpadTwoFingerGesture
|
||||
@@ -100,15 +100,18 @@ function LocationItem({ location, index, navigation }: LocationItemProps) {
|
||||
/>
|
||||
</View>
|
||||
<View style={tw`mx-4 flex-1`}>
|
||||
<Text numberOfLines={1} style={tw`text-ink text-sm font-semibold`}>
|
||||
<Text numberOfLines={1} style={tw`text-sm font-semibold text-ink`}>
|
||||
{location.name}
|
||||
</Text>
|
||||
<View style={tw`bg-app-highlight mt-0.5 self-start rounded py-[1px] px-1`}>
|
||||
<Text numberOfLines={1} style={tw`text-ink-dull text-xs font-semibold`}>
|
||||
<View style={tw`mt-0.5 self-start rounded bg-app-highlight py-[1px] px-1`}>
|
||||
<Text numberOfLines={1} style={tw`text-xs font-semibold text-ink-dull`}>
|
||||
{location.node.name}
|
||||
</Text>
|
||||
</View>
|
||||
<Text numberOfLines={1} style={tw`text-ink-dull mt-0.5 text-[10px] font-semibold`}>
|
||||
<Text
|
||||
numberOfLines={1}
|
||||
style={tw`mt-0.5 text-[10px] font-semibold text-ink-dull`}
|
||||
>
|
||||
{location.path}
|
||||
</Text>
|
||||
</View>
|
||||
|
||||
@@ -28,7 +28,11 @@ function TagItem({ tag, index }: { tag: Tag; index: number }) {
|
||||
<Animated.View
|
||||
style={[tw`flex flex-row items-center`, { transform: [{ translateX: translate }] }]}
|
||||
>
|
||||
<UpdateTagModal tag={tag} ref={updateTagModalRef} onSubmit={() => swipeable.close()} />
|
||||
<UpdateTagModal
|
||||
tag={tag}
|
||||
ref={updateTagModalRef}
|
||||
onSubmit={() => swipeable.close()}
|
||||
/>
|
||||
<AnimatedButton onPress={() => updateTagModalRef.current?.present()}>
|
||||
<Pen size={18} color="white" />
|
||||
</AnimatedButton>
|
||||
@@ -47,7 +51,7 @@ function TagItem({ tag, index }: { tag: Tag; index: number }) {
|
||||
return (
|
||||
<Swipeable
|
||||
containerStyle={twStyle(
|
||||
'border-app-line bg-app-overlay rounded-lg border px-4 py-3',
|
||||
'rounded-lg border border-app-line bg-app-overlay px-4 py-3',
|
||||
index !== 0 && 'mt-2'
|
||||
)}
|
||||
enableTrackpadTwoFingerGesture
|
||||
@@ -55,8 +59,10 @@ function TagItem({ tag, index }: { tag: Tag; index: number }) {
|
||||
>
|
||||
<View style={tw`flex flex-row items-center justify-between`}>
|
||||
<View style={tw`flex flex-row`}>
|
||||
<View style={twStyle({ backgroundColor: tag.color! }, 'h-4 w-4 rounded-full')} />
|
||||
<Text style={tw`text-ink ml-3`}>{tag.name}</Text>
|
||||
<View
|
||||
style={twStyle({ backgroundColor: tag.color! }, 'h-4 w-4 rounded-full')}
|
||||
/>
|
||||
<Text style={tw`ml-3 text-ink`}>{tag.name}</Text>
|
||||
</View>
|
||||
<CaretRight color={tw.color('ink-dull')} size={18} />
|
||||
</View>
|
||||
|
||||
8
apps/web/.eslintrc.js
Normal file
8
apps/web/.eslintrc.js
Normal file
@@ -0,0 +1,8 @@
|
||||
module.exports = {
|
||||
extends: [require.resolve('@sd/config/eslint/web.js')],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
},
|
||||
ignorePatterns: ['playwright.config.ts', 'tests/**/*']
|
||||
};
|
||||
@@ -16,13 +16,22 @@ export function App() {
|
||||
<div className="flex h-screen w-screen flex-row divide-x divide-gray-300">
|
||||
<div className="flex flex-col space-y-2 p-2">
|
||||
<div className="space-x-2">
|
||||
<button className={ButtonStyles} onClick={() => createDb.mutate('pullOperations')}>
|
||||
<button
|
||||
className={ButtonStyles}
|
||||
onClick={() => createDb.mutate('pullOperations')}
|
||||
>
|
||||
Add Database
|
||||
</button>
|
||||
<button className={ButtonStyles} onClick={() => removeDbs.mutate('pullOperations')}>
|
||||
<button
|
||||
className={ButtonStyles}
|
||||
onClick={() => removeDbs.mutate('pullOperations')}
|
||||
>
|
||||
Remove Databases
|
||||
</button>
|
||||
<button className={ButtonStyles} onClick={() => testCreate.mutate('testCreate')}>
|
||||
<button
|
||||
className={ButtonStyles}
|
||||
onClick={() => testCreate.mutate('testCreate')}
|
||||
>
|
||||
Test Create
|
||||
</button>
|
||||
</div>
|
||||
@@ -143,9 +152,13 @@ function OperationList(props: { db: string }) {
|
||||
<tr key={message.id}>
|
||||
<td className="border border-transparent">{message.id}</td>
|
||||
<td className="border border-transparent">
|
||||
{new Date(Number(message.timestamp) / 10000000).toLocaleTimeString()}
|
||||
{new Date(
|
||||
Number(message.timestamp) / 10000000
|
||||
).toLocaleTimeString()}
|
||||
</td>
|
||||
<td className="border border-transparent">
|
||||
{messageType(message.typ)}
|
||||
</td>
|
||||
<td className="border border-transparent">{messageType(message.typ)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</table>
|
||||
|
||||
@@ -11,7 +11,9 @@ export default (props: { objectId: number }) => {
|
||||
const submitPlausibleEvent = usePlausibleEvent();
|
||||
|
||||
const tags = useLibraryQuery(['tags.list'], { suspense: true });
|
||||
const tagsForObject = useLibraryQuery(['tags.getForObject', props.objectId], { suspense: true });
|
||||
const tagsForObject = useLibraryQuery(['tags.getForObject', props.objectId], {
|
||||
suspense: true
|
||||
});
|
||||
|
||||
const assignTag = useLibraryMutation('tags.assign', {
|
||||
onSuccess: () => {
|
||||
@@ -42,7 +44,9 @@ export default (props: { objectId: number }) => {
|
||||
iconProps={{ size: 15 }}
|
||||
keybind="⌘N"
|
||||
onClick={() => {
|
||||
dialogManager.create((dp) => <CreateDialog {...dp} assignToObject={props.objectId} />);
|
||||
dialogManager.create((dp) => (
|
||||
<CreateDialog {...dp} assignToObject={props.objectId} />
|
||||
));
|
||||
}}
|
||||
/>
|
||||
<Menu.Separator className={clsx('mx-0 mb-0 transition', isScrolled && 'shadow')} />
|
||||
@@ -91,7 +95,8 @@ export default (props: { objectId: number }) => {
|
||||
<div
|
||||
className="mr-0.5 h-[15px] w-[15px] shrink-0 rounded-full border"
|
||||
style={{
|
||||
backgroundColor: active && tag.color ? tag.color : 'transparent',
|
||||
backgroundColor:
|
||||
active && tag.color ? tag.color : 'transparent',
|
||||
borderColor: tag.color || '#efefef'
|
||||
}}
|
||||
/>
|
||||
|
||||
@@ -116,14 +116,16 @@ export default (props: PropsWithChildren) => {
|
||||
<CM.SubMenu label="More actions..." icon={Plus}>
|
||||
<CM.Item
|
||||
onClick={() =>
|
||||
store.locationId && generateThumbsForLocation.mutate({ id: store.locationId, path: '' })
|
||||
store.locationId &&
|
||||
generateThumbsForLocation.mutate({ id: store.locationId, path: '' })
|
||||
}
|
||||
label="Regen Thumbnails"
|
||||
icon={Image}
|
||||
/>
|
||||
<CM.Item
|
||||
onClick={() =>
|
||||
store.locationId && objectValidator.mutate({ id: store.locationId, path: '' })
|
||||
store.locationId &&
|
||||
objectValidator.mutate({ id: store.locationId, path: '' })
|
||||
}
|
||||
label="Generate Checksums"
|
||||
icon={ShieldCheck}
|
||||
|
||||
@@ -161,7 +161,11 @@ export default ({ data, className, ...props }: Props) => {
|
||||
onClick={() => {
|
||||
if (keyManagerUnlocked && hasMountedKeys) {
|
||||
dialogManager.create((dp) => (
|
||||
<EncryptDialog {...dp} location_id={store.locationId!} path_id={data.item.id} />
|
||||
<EncryptDialog
|
||||
{...dp}
|
||||
location_id={store.locationId!}
|
||||
path_id={data.item.id}
|
||||
/>
|
||||
));
|
||||
} else if (!keyManagerUnlocked) {
|
||||
showAlertDialog({
|
||||
@@ -184,7 +188,11 @@ export default ({ data, className, ...props }: Props) => {
|
||||
onClick={() => {
|
||||
if (keyManagerUnlocked) {
|
||||
dialogManager.create((dp) => (
|
||||
<DecryptDialog {...dp} location_id={store.locationId!} path_id={data.item.id} />
|
||||
<DecryptDialog
|
||||
{...dp}
|
||||
location_id={store.locationId!}
|
||||
path_id={data.item.id}
|
||||
/>
|
||||
));
|
||||
} else {
|
||||
showAlertDialog({
|
||||
|
||||
@@ -42,8 +42,7 @@ export default (props: Props) => {
|
||||
onSuccess: () => {
|
||||
showAlertDialog({
|
||||
title: 'Success',
|
||||
value:
|
||||
'The decryption job has started successfully. You may track the progress in the job overview panel.'
|
||||
value: 'The decryption job has started successfully. You may track the progress in the job overview panel.'
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
@@ -123,7 +122,9 @@ export default (props: Props) => {
|
||||
checked={form.watch('mountAssociatedKey')}
|
||||
onCheckedChange={(e) => form.setValue('mountAssociatedKey', e)}
|
||||
/>
|
||||
<span className="ml-3 mt-0.5 text-xs font-medium">Automatically mount key</span>
|
||||
<span className="ml-3 mt-0.5 text-xs font-medium">
|
||||
Automatically mount key
|
||||
</span>
|
||||
<Tooltip label="The key linked with the file will be automatically mounted">
|
||||
<Info className="ml-1.5 mt-0.5 h-4 w-4 text-ink-faint" />
|
||||
</Tooltip>
|
||||
@@ -143,7 +144,9 @@ export default (props: Props) => {
|
||||
size="sm"
|
||||
{...form.register('saveToKeyManager')}
|
||||
/>
|
||||
<span className="ml-3 mt-0.5 text-xs font-medium">Save to Key Manager</span>
|
||||
<span className="ml-3 mt-0.5 text-xs font-medium">
|
||||
Save to Key Manager
|
||||
</span>
|
||||
<Tooltip label="This key will be saved to the key manager">
|
||||
<Info className="ml-1.5 mt-0.5 h-4 w-4 text-ink-faint" />
|
||||
</Tooltip>
|
||||
|
||||
@@ -48,8 +48,7 @@ export default (props: Props) => {
|
||||
onSuccess: () => {
|
||||
showAlertDialog({
|
||||
title: 'Success',
|
||||
value:
|
||||
'The encryption job has started successfully. You may track the progress in the job overview panel.'
|
||||
value: 'The encryption job has started successfully. You may track the progress in the job overview panel.'
|
||||
});
|
||||
},
|
||||
onError: () => {
|
||||
@@ -154,9 +153,15 @@ export default (props: Props) => {
|
||||
<SelectOption value="Argon2id-s">Argon2id (standard)</SelectOption>
|
||||
<SelectOption value="Argon2id-h">Argon2id (hardened)</SelectOption>
|
||||
<SelectOption value="Argon2id-p">Argon2id (paranoid)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-s">BLAKE3-Balloon (standard)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-h">BLAKE3-Balloon (hardened)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-p">BLAKE3-Balloon (paranoid)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-s">
|
||||
BLAKE3-Balloon (standard)
|
||||
</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-h">
|
||||
BLAKE3-Balloon (hardened)
|
||||
</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-p">
|
||||
BLAKE3-Balloon (paranoid)
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -46,7 +46,10 @@ const GridViewItem = memo(({ data, selected, index, ...props }: GridViewItemProp
|
||||
<RenameTextBox
|
||||
filePathData={filePathData}
|
||||
selected={selected}
|
||||
className={clsx('text-center font-medium', selected && 'bg-accent text-white')}
|
||||
className={clsx(
|
||||
'text-center font-medium',
|
||||
selected && 'bg-accent text-white'
|
||||
)}
|
||||
style={{
|
||||
maxHeight: explorerStore.gridItemSize / 3
|
||||
}}
|
||||
@@ -109,7 +112,8 @@ export default () => {
|
||||
const index = explorerStore.selectedRowIndex;
|
||||
if (
|
||||
explorerStore.showInspector &&
|
||||
((lastSelectedIndex === -1 && index !== -1) || (lastSelectedIndex !== -1 && index === -1))
|
||||
((lastSelectedIndex === -1 && index !== -1) ||
|
||||
(lastSelectedIndex !== -1 && index === -1))
|
||||
) {
|
||||
handleWindowResize();
|
||||
}
|
||||
@@ -186,7 +190,12 @@ export default () => {
|
||||
|
||||
if (!item) return null;
|
||||
return (
|
||||
<GridViewItem key={item.item.id} data={item} selected={isSelected} index={index} />
|
||||
<GridViewItem
|
||||
key={item.item.id}
|
||||
data={item}
|
||||
selected={isSelected}
|
||||
index={index}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
@@ -26,7 +26,10 @@ export default function Note(props: Props) {
|
||||
);
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const debouncedNote = useCallback((note: string) => debounce(note), [props.data.id, fileSetNote]);
|
||||
const debouncedNote = useCallback(
|
||||
(note: string) => debounce(note),
|
||||
[props.data.id, fileSetNote]
|
||||
);
|
||||
|
||||
// when input is updated, cache note
|
||||
function handleNoteUpdate(e: React.ChangeEvent<HTMLTextAreaElement>) {
|
||||
|
||||
@@ -120,10 +120,18 @@ export const Inspector = ({ data, context, onScroll, ...elementProps }: Props) =
|
||||
<Divider />
|
||||
<MetaContainer>
|
||||
<div className="flex flex-wrap gap-1 overflow-hidden">
|
||||
<InfoPill>{isDir ? 'Folder' : ObjectKind[objectData?.kind || 0]}</InfoPill>
|
||||
{filePathData?.extension && <InfoPill>{filePathData.extension}</InfoPill>}
|
||||
<InfoPill>
|
||||
{isDir ? 'Folder' : ObjectKind[objectData?.kind || 0]}
|
||||
</InfoPill>
|
||||
{filePathData?.extension && (
|
||||
<InfoPill>{filePathData.extension}</InfoPill>
|
||||
)}
|
||||
{tags?.data?.map((tag) => (
|
||||
<Tooltip key={tag.id} label={tag.name || ''} className="flex overflow-hidden">
|
||||
<Tooltip
|
||||
key={tag.id}
|
||||
label={tag.name || ''}
|
||||
className="flex overflow-hidden"
|
||||
>
|
||||
<InfoPill
|
||||
className="truncate !text-white"
|
||||
style={{ backgroundColor: tag.color + 'CC' }}
|
||||
@@ -149,13 +157,17 @@ export const Inspector = ({ data, context, onScroll, ...elementProps }: Props) =
|
||||
<MetaTextLine>
|
||||
<InspectorIcon component={Cube} />
|
||||
<span className="mr-1.5">Size</span>
|
||||
<MetaValue>{formatBytes(Number(filePathData?.size_in_bytes || 0))}</MetaValue>
|
||||
<MetaValue>
|
||||
{formatBytes(Number(filePathData?.size_in_bytes || 0))}
|
||||
</MetaValue>
|
||||
</MetaTextLine>
|
||||
{fullObjectData.data?.media_data?.duration_seconds && (
|
||||
<MetaTextLine>
|
||||
<InspectorIcon component={Clock} />
|
||||
<span className="mr-1.5">Duration</span>
|
||||
<MetaValue>{fullObjectData.data.media_data.duration_seconds}</MetaValue>
|
||||
<MetaValue>
|
||||
{fullObjectData.data.media_data.duration_seconds}
|
||||
</MetaValue>
|
||||
</MetaTextLine>
|
||||
)}
|
||||
</MetaContainer>
|
||||
@@ -165,14 +177,18 @@ export const Inspector = ({ data, context, onScroll, ...elementProps }: Props) =
|
||||
<MetaTextLine>
|
||||
<InspectorIcon component={Clock} />
|
||||
<MetaKeyName className="mr-1.5">Created</MetaKeyName>
|
||||
<MetaValue>{dayjs(item?.date_created).format('MMM Do YYYY')}</MetaValue>
|
||||
<MetaValue>
|
||||
{dayjs(item?.date_created).format('MMM Do YYYY')}
|
||||
</MetaValue>
|
||||
</MetaTextLine>
|
||||
</Tooltip>
|
||||
<Tooltip label={dayjs(item?.date_created).format('h:mm:ss a')}>
|
||||
<MetaTextLine>
|
||||
<InspectorIcon component={Barcode} />
|
||||
<MetaKeyName className="mr-1.5">Indexed</MetaKeyName>
|
||||
<MetaValue>{dayjs(filePathData?.date_indexed).format('MMM Do YYYY')}</MetaValue>
|
||||
<MetaValue>
|
||||
{dayjs(filePathData?.date_indexed).format('MMM Do YYYY')}
|
||||
</MetaValue>
|
||||
</MetaTextLine>
|
||||
</Tooltip>
|
||||
</MetaContainer>
|
||||
@@ -193,8 +209,12 @@ export const Inspector = ({ data, context, onScroll, ...elementProps }: Props) =
|
||||
<Tooltip label={filePathData?.integrity_checksum || ''}>
|
||||
<MetaTextLine>
|
||||
<InspectorIcon component={CircleWavyCheck} />
|
||||
<MetaKeyName className="mr-1.5">Checksum</MetaKeyName>
|
||||
<MetaValue>{filePathData?.integrity_checksum}</MetaValue>
|
||||
<MetaKeyName className="mr-1.5">
|
||||
Checksum
|
||||
</MetaKeyName>
|
||||
<MetaValue>
|
||||
{filePathData?.integrity_checksum}
|
||||
</MetaValue>
|
||||
</MetaTextLine>
|
||||
</Tooltip>
|
||||
)}
|
||||
@@ -202,7 +222,9 @@ export const Inspector = ({ data, context, onScroll, ...elementProps }: Props) =
|
||||
<Tooltip label={pub_id || ''}>
|
||||
<MetaTextLine>
|
||||
<InspectorIcon component={Hash} />
|
||||
<MetaKeyName className="mr-1.5">Object ID</MetaKeyName>
|
||||
<MetaKeyName className="mr-1.5">
|
||||
Object ID
|
||||
</MetaKeyName>
|
||||
<MetaValue>{pub_id}</MetaValue>
|
||||
</MetaTextLine>
|
||||
</Tooltip>
|
||||
|
||||
@@ -182,7 +182,12 @@ export default () => {
|
||||
const tableHeaderHeight = 34;
|
||||
const tableEnd = virtualRows[virtualRows.length - 1]?.end || 0;
|
||||
const padding =
|
||||
scrollHeight - TOP_BAR_HEIGHT - tableHeaderHeight - paddingY - tableEnd - scrollBarWidth;
|
||||
scrollHeight -
|
||||
TOP_BAR_HEIGHT -
|
||||
tableHeaderHeight -
|
||||
paddingY -
|
||||
tableEnd -
|
||||
scrollBarWidth;
|
||||
return padding > 0 ? padding : paddingY;
|
||||
}, [virtualRows]);
|
||||
|
||||
@@ -195,7 +200,14 @@ export default () => {
|
||||
return {
|
||||
...sizing,
|
||||
...(scrollWidth && nameWidth
|
||||
? { Name: nameWidth + scrollWidth - paddingX * 2 - scrollBarWidth - tableLength }
|
||||
? {
|
||||
Name:
|
||||
nameWidth +
|
||||
scrollWidth -
|
||||
paddingX * 2 -
|
||||
scrollBarWidth -
|
||||
tableLength
|
||||
}
|
||||
: {})
|
||||
};
|
||||
});
|
||||
@@ -233,7 +245,8 @@ export default () => {
|
||||
const index = explorerStore.selectedRowIndex;
|
||||
if (
|
||||
explorerStore.showInspector &&
|
||||
((lastSelectedIndex === -1 && index !== -1) || (lastSelectedIndex !== -1 && index === -1))
|
||||
((lastSelectedIndex === -1 && index !== -1) ||
|
||||
(lastSelectedIndex !== -1 && index === -1))
|
||||
) {
|
||||
handleResize();
|
||||
}
|
||||
@@ -258,7 +271,9 @@ export default () => {
|
||||
(e) => {
|
||||
e.preventDefault();
|
||||
if (explorerStore.selectedRowIndex > 0) {
|
||||
const currentIndex = rows.findIndex((row) => row.index === explorerStore.selectedRowIndex);
|
||||
const currentIndex = rows.findIndex(
|
||||
(row) => row.index === explorerStore.selectedRowIndex
|
||||
);
|
||||
const newIndex = rows[currentIndex - 1]?.index;
|
||||
if (newIndex !== undefined) getExplorerStore().selectedRowIndex = newIndex;
|
||||
}
|
||||
@@ -275,7 +290,9 @@ export default () => {
|
||||
explorerStore.selectedRowIndex !== -1 &&
|
||||
explorerStore.selectedRowIndex !== (data.length ?? 1) - 1
|
||||
) {
|
||||
const currentIndex = rows.findIndex((row) => row.index === explorerStore.selectedRowIndex);
|
||||
const currentIndex = rows.findIndex(
|
||||
(row) => row.index === explorerStore.selectedRowIndex
|
||||
);
|
||||
const newIndex = rows[currentIndex + 1]?.index;
|
||||
if (newIndex !== undefined) getExplorerStore().selectedRowIndex = newIndex;
|
||||
}
|
||||
@@ -293,7 +310,11 @@ export default () => {
|
||||
)}
|
||||
>
|
||||
{table.getHeaderGroups().map((headerGroup) => (
|
||||
<div role="rowheader" key={headerGroup.id} className="flex border-b border-app-line/50">
|
||||
<div
|
||||
role="rowheader"
|
||||
key={headerGroup.id}
|
||||
className="flex border-b border-app-line/50"
|
||||
>
|
||||
{headerGroup.headers.map((header, i) => {
|
||||
const size = header.column.getSize();
|
||||
return (
|
||||
@@ -313,7 +334,10 @@ export default () => {
|
||||
>
|
||||
{header.isPlaceholder ? null : (
|
||||
<div className={clsx('flex items-center')}>
|
||||
{flexRender(header.column.columnDef.header, header.getContext())}
|
||||
{flexRender(
|
||||
header.column.columnDef.header,
|
||||
header.getContext()
|
||||
)}
|
||||
<div className="flex-1" />
|
||||
|
||||
{{
|
||||
@@ -322,7 +346,8 @@ export default () => {
|
||||
}[header.column.getIsSorted() as string] ?? null}
|
||||
|
||||
{(i !== headerGroup.headers.length - 1 ||
|
||||
(i === headerGroup.headers.length - 1 && !locked)) && (
|
||||
(i === headerGroup.headers.length - 1 &&
|
||||
!locked)) && (
|
||||
<div
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
onMouseDown={(e) => {
|
||||
@@ -348,7 +373,11 @@ export default () => {
|
||||
const row = rows[virtualRow.index]!;
|
||||
const selected = explorerStore.selectedRowIndex === row.index;
|
||||
return (
|
||||
<div key={row.id} className="flex pl-4 pr-3" style={{ height: `${virtualRow.size}px` }}>
|
||||
<div
|
||||
key={row.id}
|
||||
className="flex pl-4 pr-3"
|
||||
style={{ height: `${virtualRow.size}px` }}
|
||||
>
|
||||
<ListViewItem
|
||||
row={row}
|
||||
index={virtualRow.index}
|
||||
|
||||
@@ -161,7 +161,8 @@ export function QuickPreview({ libraryUuid, transformOrigin }: QuickPreviewProps
|
||||
if (!show || explorerItem.current == null) return null;
|
||||
|
||||
const { item } = explorerItem.current;
|
||||
const locationId = 'location_id' in item ? item.location_id : explorerStore.locationId;
|
||||
const locationId =
|
||||
'location_id' in item ? item.location_id : explorerStore.locationId;
|
||||
if (locationId == null) {
|
||||
onPreviewError();
|
||||
return null;
|
||||
@@ -192,13 +193,18 @@ export function QuickPreview({ libraryUuid, transformOrigin }: QuickPreviewProps
|
||||
>
|
||||
<div className="!pointer-events-auto h-5/6 w-11/12 rounded-md border border-app-line bg-app-box text-ink shadow-app-shade">
|
||||
<nav className="flex w-full flex-row">
|
||||
<Dialog.Close className="ml-2 text-ink-dull" aria-label="Close">
|
||||
<Dialog.Close
|
||||
className="ml-2 text-ink-dull"
|
||||
aria-label="Close"
|
||||
>
|
||||
<XCircle size={16} />
|
||||
</Dialog.Close>
|
||||
<Dialog.Title className="mx-auto my-1 font-bold">
|
||||
Preview -{' '}
|
||||
<span className="inline-block max-w-xs truncate align-sub text-sm text-ink-dull">
|
||||
{'name' in item && item.name ? item.name : 'Unkown Object'}
|
||||
{'name' in item && item.name
|
||||
? item.name
|
||||
: 'Unkown Object'}
|
||||
</span>
|
||||
</Dialog.Title>
|
||||
</nav>
|
||||
|
||||
@@ -19,7 +19,10 @@ export default forwardRef<HTMLInputElement, Props>((props, forwardedRef) => {
|
||||
if ((event.key === 'f' && event.metaKey) || event.ctrlKey) {
|
||||
event.preventDefault();
|
||||
forwardedRef?.current?.focus();
|
||||
} else if (forwardedRef?.current === document.activeElement && event.key === 'Escape') {
|
||||
} else if (
|
||||
forwardedRef?.current === document.activeElement &&
|
||||
event.key === 'Escape'
|
||||
) {
|
||||
forwardedRef.current?.blur();
|
||||
setSearchValue('');
|
||||
}
|
||||
@@ -39,7 +42,10 @@ export default forwardRef<HTMLInputElement, Props>((props, forwardedRef) => {
|
||||
else if (forwardedRef) forwardedRef.current = el;
|
||||
}}
|
||||
placeholder="Search"
|
||||
className={clsx('w-52 transition-all duration-200 focus-within:w-60', props.className)}
|
||||
className={clsx(
|
||||
'w-52 transition-all duration-200 focus-within:w-60',
|
||||
props.className
|
||||
)}
|
||||
size="sm"
|
||||
onChange={(e) => setSearchValue(e.target.value)}
|
||||
onBlur={() => setSearchValue('')}
|
||||
@@ -51,11 +57,20 @@ export default forwardRef<HTMLInputElement, Props>((props, forwardedRef) => {
|
||||
)}
|
||||
>
|
||||
{platform === 'browser' ? (
|
||||
<Shortcut chars="⌘F" aria-label={'Press Command-F to focus search bar'} />
|
||||
<Shortcut
|
||||
chars="⌘F"
|
||||
aria-label={'Press Command-F to focus search bar'}
|
||||
/>
|
||||
) : os === 'macOS' ? (
|
||||
<Shortcut chars="⌘F" aria-label={'Press Command-F to focus search bar'} />
|
||||
<Shortcut
|
||||
chars="⌘F"
|
||||
aria-label={'Press Command-F to focus search bar'}
|
||||
/>
|
||||
) : (
|
||||
<Shortcut chars="CTRL+F" aria-label={'Press CTRL-F to focus search bar'} />
|
||||
<Shortcut
|
||||
chars="CTRL+F"
|
||||
aria-label={'Press CTRL-F to focus search bar'}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ export default () => {
|
||||
}, [topBarRef]);
|
||||
|
||||
const topBarCondition =
|
||||
(topBarWidth < 1000 && countToolOptions >= 8) || (topBarWidth < 600 && countToolOptions >= 6);
|
||||
(topBarWidth < 1000 && countToolOptions >= 8) ||
|
||||
(topBarWidth < 600 && countToolOptions >= 6);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -70,13 +71,23 @@ export default () => {
|
||||
|
||||
<SearchBar formClassName="justify-center" ref={searchRef} />
|
||||
|
||||
<div data-tauri-drag-region className="flex flex-row justify-end w-full">
|
||||
<div data-tauri-drag-region className={`gap-0 ${topBarCondition ? 'hidden' : 'flex'}`}>
|
||||
<div data-tauri-drag-region className="flex w-full flex-row justify-end">
|
||||
<div
|
||||
data-tauri-drag-region
|
||||
className={`gap-0 ${topBarCondition ? 'hidden' : 'flex'}`}
|
||||
>
|
||||
{toolBarRouteOptions[getPageName].options.map((group) => {
|
||||
return (Object.keys(group) as groupKeys[]).map((groupKey) => {
|
||||
return group[groupKey]?.map(
|
||||
(
|
||||
{ icon, onClick, popOverComponent, toolTipLabel, topBarActive, individual },
|
||||
{
|
||||
icon,
|
||||
onClick,
|
||||
popOverComponent,
|
||||
toolTipLabel,
|
||||
topBarActive,
|
||||
individual
|
||||
},
|
||||
index
|
||||
) => {
|
||||
const groupCount = Object.keys(group).length;
|
||||
@@ -108,7 +119,9 @@ export default () => {
|
||||
</TopBarButton>
|
||||
}
|
||||
>
|
||||
<div className="block w-[250px] ">{popOverComponent}</div>
|
||||
<div className="block w-[250px] ">
|
||||
{popOverComponent}
|
||||
</div>
|
||||
</Popover>
|
||||
) : (
|
||||
<TopBarButton
|
||||
|
||||
@@ -13,7 +13,7 @@ export interface TopBarButtonProps {
|
||||
}
|
||||
|
||||
const topBarButtonStyle = cva(
|
||||
'text-ink hover:text-ink text-md relative hover:bg-app-selected radix-state-open:bg-app-selected mr-[1px] flex border-none !p-0.5 font-medium outline-none transition-colors duration-100',
|
||||
'text-md relative mr-[1px] flex border-none !p-0.5 font-medium text-ink outline-none transition-colors duration-100 hover:bg-app-selected hover:text-ink radix-state-open:bg-app-selected',
|
||||
{
|
||||
variants: {
|
||||
active: {
|
||||
@@ -37,7 +37,11 @@ const topBarButtonStyle = cva(
|
||||
export default forwardRef<HTMLButtonElement, TopBarButtonProps>(
|
||||
({ active, rounding, className, ...props }, ref) => {
|
||||
return (
|
||||
<Button {...props} ref={ref} className={topBarButtonStyle({ active, rounding, className })}>
|
||||
<Button
|
||||
{...props}
|
||||
ref={ref}
|
||||
className={topBarButtonStyle({ active, rounding, className })}
|
||||
>
|
||||
{props.children}
|
||||
{props.checkIcon && active && (
|
||||
<Check className="absolute right-2 m-0.5 h-5 w-5 text-ink-dull" />
|
||||
|
||||
@@ -23,11 +23,14 @@ export default ({ className = '' }: Props) => {
|
||||
</TopBarButton>
|
||||
}
|
||||
>
|
||||
<div className="flex flex-col p-2 overflow-hidden">
|
||||
<div className="flex flex-col overflow-hidden p-2">
|
||||
{toolBarRouteOptions[getPageName].options.map((group) => {
|
||||
return (Object.keys(group) as groupKeys[]).map((groupKey) => {
|
||||
return group[groupKey]?.map(
|
||||
({ icon, onClick, popOverComponent, toolTipLabel, topBarActive }, index) => {
|
||||
(
|
||||
{ icon, onClick, popOverComponent, toolTipLabel, topBarActive },
|
||||
index
|
||||
) => {
|
||||
const groupCount = Object.keys(group).length;
|
||||
const groupIndex = Object.keys(group).indexOf(groupKey);
|
||||
return (
|
||||
@@ -42,7 +45,7 @@ export default ({ className = '' }: Props) => {
|
||||
onClick={onClick}
|
||||
checkIcon={true}
|
||||
>
|
||||
<div className="flex items-center justify-between w-full">
|
||||
<div className="flex w-full items-center justify-between">
|
||||
<div className="flex items-center gap-1">
|
||||
{icon}
|
||||
{toolTipLabel}
|
||||
@@ -51,7 +54,9 @@ export default ({ className = '' }: Props) => {
|
||||
</TopBarButton>
|
||||
}
|
||||
>
|
||||
<div className="block w-[250px] ">{popOverComponent}</div>
|
||||
<div className="block w-[250px] ">
|
||||
{popOverComponent}
|
||||
</div>
|
||||
</Popover>
|
||||
) : (
|
||||
<TopBarButton
|
||||
|
||||
@@ -33,7 +33,7 @@ export default function Explorer(props: Props) {
|
||||
}, [locationId]);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full h-screen bg-app">
|
||||
<div className="flex h-screen w-full flex-col bg-app">
|
||||
<TopBar />
|
||||
|
||||
<div className="flex flex-1">
|
||||
@@ -45,7 +45,10 @@ export default function Explorer(props: Props) {
|
||||
|
||||
{expStore.showInspector && props.data?.items[expStore.selectedRowIndex] && (
|
||||
<div className="w-[260px] shrink-0">
|
||||
<Inspector data={props.data?.items[expStore.selectedRowIndex]} onScroll={onScroll} />
|
||||
<Inspector
|
||||
data={props.data?.items[expStore.selectedRowIndex]}
|
||||
onScroll={onScroll}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -103,7 +103,11 @@ export const Key = ({ data }: { data: Key }) => {
|
||||
<KeyIcon
|
||||
className={clsx(
|
||||
'ml-1 mr-3 h-5 w-5',
|
||||
data.mounted ? (data.locked ? 'text-accent' : 'text-accent') : 'text-gray-400/80'
|
||||
data.mounted
|
||||
? data.locked
|
||||
? 'text-accent'
|
||||
: 'text-accent'
|
||||
: 'text-gray-400/80'
|
||||
)}
|
||||
/>
|
||||
<div className="flex flex-col ">
|
||||
@@ -111,7 +115,9 @@ export const Key = ({ data }: { data: Key }) => {
|
||||
<div className="font-semibold">{data.name}</div>
|
||||
{data.mounted && (
|
||||
<div className="ml-2 inline rounded bg-gray-500 px-1 text-[8pt] font-medium text-gray-300">
|
||||
{data.nodes?.length || 0 > 0 ? `${data.nodes?.length || 0} nodes` : 'This node'}
|
||||
{data.nodes?.length || 0 > 0
|
||||
? `${data.nodes?.length || 0} nodes`
|
||||
: 'This node'}
|
||||
</div>
|
||||
)}
|
||||
{data.default && (
|
||||
|
||||
@@ -41,7 +41,12 @@ export default () => {
|
||||
<div className="mb-1 p-3">
|
||||
<KeyHeading>Mount key</KeyHeading>
|
||||
|
||||
<PasswordInput ref={ref} value={key} onChange={(e) => setKey(e.target.value)} autoFocus />
|
||||
<PasswordInput
|
||||
ref={ref}
|
||||
value={key}
|
||||
onChange={(e) => setKey(e.target.value)}
|
||||
autoFocus
|
||||
/>
|
||||
|
||||
<div className="flex flex-row space-x-2">
|
||||
<div className="relative mt-2 flex grow">
|
||||
@@ -115,9 +120,15 @@ export default () => {
|
||||
<SelectOption value="Argon2id-s">Argon2id (standard)</SelectOption>
|
||||
<SelectOption value="Argon2id-h">Argon2id (hardened)</SelectOption>
|
||||
<SelectOption value="Argon2id-p">Argon2id (paranoid)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-s">BLAKE3-Balloon (standard)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-h">BLAKE3-Balloon (hardened)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-p">BLAKE3-Balloon (paranoid)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-s">
|
||||
BLAKE3-Balloon (standard)
|
||||
</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-h">
|
||||
BLAKE3-Balloon (hardened)
|
||||
</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-p">
|
||||
BLAKE3-Balloon (paranoid)
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -49,7 +49,10 @@ export default () => {
|
||||
if (masterPassword !== '') {
|
||||
setMasterPassword('');
|
||||
setSecretKey('');
|
||||
unlockKeyManager.mutate({ password: masterPassword, secret_key: secretKey });
|
||||
unlockKeyManager.mutate({
|
||||
password: masterPassword,
|
||||
secret_key: secretKey
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -20,7 +20,7 @@ export default () => {
|
||||
const { library } = useClientContext();
|
||||
|
||||
return (
|
||||
<div className="flex flex-col pb-10 overflow-x-hidden overflow-y-scroll no-scrollbar mask-fade-out grow">
|
||||
<div className="no-scrollbar mask-fade-out flex grow flex-col overflow-x-hidden overflow-y-scroll pb-10">
|
||||
<div className="space-y-0.5">
|
||||
<SidebarLink to="overview">
|
||||
<Icon component={Planet} />
|
||||
|
||||
@@ -73,7 +73,8 @@ export default () => {
|
||||
size="sm"
|
||||
variant="gray"
|
||||
onClick={() => {
|
||||
if (nodeState?.data?.data_path) platform.openPath!(nodeState?.data?.data_path);
|
||||
if (nodeState?.data?.data_path)
|
||||
platform.openPath!(nodeState?.data?.data_path);
|
||||
}}
|
||||
>
|
||||
Open
|
||||
|
||||
@@ -19,7 +19,7 @@ export default () => {
|
||||
className="text-ink-faint ring-offset-sidebar"
|
||||
>
|
||||
<Tooltip label="Settings">
|
||||
<Gear className="w-5 h-5" />
|
||||
<Gear className="h-5 w-5" />
|
||||
</Tooltip>
|
||||
</ButtonLink>
|
||||
<Popover
|
||||
|
||||
@@ -8,6 +8,6 @@ export default () => {
|
||||
return isRunningJob ? (
|
||||
<Loader className="h-[20px] w-[20px]" />
|
||||
) : (
|
||||
<CheckCircle className="w-5 h-5" />
|
||||
<CheckCircle className="h-5 w-5" />
|
||||
);
|
||||
};
|
||||
|
||||
@@ -36,7 +36,9 @@ const getNiceData = (job: JobReport): Record<string, JobNiceData> => ({
|
||||
icon: Camera
|
||||
},
|
||||
file_identifier: {
|
||||
name: `Extracted metadata for ${numberWithCommas(job.metadata?.total_orphan_paths || 0)} files`,
|
||||
name: `Extracted metadata for ${numberWithCommas(
|
||||
job.metadata?.total_orphan_paths || 0
|
||||
)} files`,
|
||||
icon: Eye
|
||||
},
|
||||
object_validator: {
|
||||
@@ -124,7 +126,9 @@ export function JobsManager() {
|
||||
<Job key={job.id} job={job} />
|
||||
))}
|
||||
{jobs.data?.length === 0 && runningJobs.data?.length === 0 && (
|
||||
<div className="flex h-32 items-center justify-center text-ink-dull">No jobs.</div>
|
||||
<div className="flex h-32 items-center justify-center text-ink-dull">
|
||||
No jobs.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@@ -141,6 +145,7 @@ function Job({ job }: { job: JobReport }) {
|
||||
const isRunning = job.status === 'Running';
|
||||
return (
|
||||
// Do we actually need bg-opacity-60 here? Where is the bg?
|
||||
// eslint-disable-next-line tailwindcss/migration-from-tailwind-2
|
||||
<div className="flex items-center border-b border-app-line/50 bg-opacity-60 p-2 pl-4">
|
||||
<Tooltip label={job.status}>
|
||||
<niceData.icon className={clsx('mr-3 h-5 w-5')} />
|
||||
@@ -164,7 +169,9 @@ function Job({ job }: { job: JobReport }) {
|
||||
<span className="mx-1 opacity-50">•</span>
|
||||
{
|
||||
<span className="text-xs">
|
||||
{isRunning ? 'Unknown time remaining' : dayjs(job.date_created).toNow(true) + ' ago'}
|
||||
{isRunning
|
||||
? 'Unknown time remaining'
|
||||
: dayjs(job.date_created).toNow(true) + ' ago'}
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
|
||||
@@ -29,7 +29,7 @@ export const LibrarySection = () => {
|
||||
|
||||
return (
|
||||
<SidebarLink
|
||||
className="relative w-full group"
|
||||
className="group relative w-full"
|
||||
to={`location/${location.id}`}
|
||||
key={location.id}
|
||||
>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { NavLink, NavLinkProps } from 'react-router-dom';
|
||||
import { useOperatingSystem } from '~/hooks/useOperatingSystem';
|
||||
|
||||
const styles = cva(
|
||||
'max-w ring-offset-sidebar focus:ring-accent flex grow flex-row items-center gap-0.5 truncate rounded px-2 py-1 text-sm font-medium outline-none focus:ring-2 focus:ring-offset-2',
|
||||
'max-w flex grow flex-row items-center gap-0.5 truncate rounded px-2 py-1 text-sm font-medium outline-none ring-offset-sidebar focus:ring-2 focus:ring-accent focus:ring-offset-2',
|
||||
{
|
||||
variants: {
|
||||
active: {
|
||||
|
||||
@@ -7,8 +7,8 @@ export default (
|
||||
actionArea?: React.ReactNode;
|
||||
}>
|
||||
) => (
|
||||
<div className="mt-5 group">
|
||||
<div className="flex items-center justify-between mb-1">
|
||||
<div className="group mt-5">
|
||||
<div className="mb-1 flex items-center justify-between">
|
||||
<CategoryHeading className="ml-1">{props.name}</CategoryHeading>
|
||||
<div className="text-ink-faint opacity-0 transition-all duration-300 hover:!opacity-100 group-hover:opacity-30">
|
||||
{props.actionArea}
|
||||
|
||||
@@ -14,7 +14,9 @@ export default () => {
|
||||
return (
|
||||
<div data-tauri-drag-region className={clsx('shrink-0', macOnly(os, 'h-7'))}>
|
||||
{/* We do not provide the onClick handlers for 'MacTrafficLights' because this is only used in demo mode */}
|
||||
{showControls && <MacTrafficLights className="absolute top-[13px] left-[13px] z-50" />}
|
||||
{showControls && (
|
||||
<MacTrafficLights className="absolute top-[13px] left-[13px] z-50" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { OperatingSystem } from "~/util/Platform";
|
||||
import { OperatingSystem } from '~/util/Platform';
|
||||
|
||||
export const macOnly = (platform: OperatingSystem | undefined, classnames: string) =>
|
||||
platform === 'macOS' ? classnames : '';
|
||||
|
||||
@@ -56,7 +56,9 @@ const Layout = () => {
|
||||
<QuickPreview libraryUuid={library.uuid} />
|
||||
</LibraryContextProvider>
|
||||
) : (
|
||||
<h1 className="p-4 text-white">Please select or create a library in the sidebar.</h1>
|
||||
<h1 className="p-4 text-white">
|
||||
Please select or create a library in the sidebar.
|
||||
</h1>
|
||||
)}
|
||||
</div>
|
||||
<Toasts />
|
||||
|
||||
@@ -19,7 +19,7 @@ export const Component = () => {
|
||||
)}
|
||||
>
|
||||
<DragRegion ref={ref} />
|
||||
<div className="flex flex-col w-full h-screen p-5 pt-0">
|
||||
<div className="flex h-screen w-full flex-col p-5 pt-0">
|
||||
<Outlet />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -19,7 +19,8 @@ export const Component = () => {
|
||||
const { location_id, path, limit } = useExplorerParams();
|
||||
|
||||
// we destructure this since `mutate` is a stable reference but the object it's in is not
|
||||
const { mutate: mutateQuickRescan, ...quickRescan } = useLibraryMutation('locations.quickRescan');
|
||||
const { mutate: mutateQuickRescan, ...quickRescan } =
|
||||
useLibraryMutation('locations.quickRescan');
|
||||
const explorerState = getExplorerStore();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -69,7 +69,11 @@ const StatItem = (props: StatItemProps) => {
|
||||
<span className="text-2xl">
|
||||
{isLoading && (
|
||||
<div>
|
||||
<Skeleton enableAnimation={true} baseColor={'#21212e'} highlightColor={'#13131a'} />
|
||||
<Skeleton
|
||||
enableAnimation={true}
|
||||
baseColor={'#21212e'}
|
||||
highlightColor={'#13131a'}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
@@ -96,12 +100,12 @@ export const Component = () => {
|
||||
overviewMounted = true;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col w-full h-screen">
|
||||
<div className="flex h-screen w-full flex-col">
|
||||
<ScreenHeading>Overview</ScreenHeading>
|
||||
{/* STAT HEADER */}
|
||||
<div className="flex w-full">
|
||||
{/* STAT CONTAINER */}
|
||||
<div className="flex h-20 -mb-1 overflow-hidden">
|
||||
<div className="-mb-1 flex h-20 overflow-hidden">
|
||||
{Object.entries(stats?.data || []).map(([key, value]) => {
|
||||
if (!displayableStatItems.includes(key)) return null;
|
||||
return (
|
||||
@@ -116,7 +120,7 @@ export const Component = () => {
|
||||
</div>
|
||||
<div className="grow" />
|
||||
</div>
|
||||
<div className="grid grid-cols-5 gap-3 pb-4 mt-4">
|
||||
<div className="mt-4 grid grid-cols-5 gap-3 pb-4">
|
||||
<CategoryButton icon={Heart} category="Favorites" />
|
||||
<CategoryButton icon={FileText} category="Documents" />
|
||||
<CategoryButton icon={Camera} category="Movies" />
|
||||
@@ -129,10 +133,10 @@ export const Component = () => {
|
||||
<CategoryButton icon={Heart} category="Favorites" />
|
||||
</div>
|
||||
<Card className="text-ink-dull">
|
||||
<b>Note: </b> This is a pre-alpha build of Spacedrive, many features are yet to be
|
||||
functional.
|
||||
<b>Note: </b> This is a pre-alpha build of Spacedrive, many features are yet
|
||||
to be functional.
|
||||
</Card>
|
||||
<div className="flex w-full h-4 shrink-0" />
|
||||
<div className="flex h-4 w-full shrink-0" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -145,7 +149,7 @@ interface CategoryButtonProps {
|
||||
function CategoryButton({ category, icon: Icon }: CategoryButtonProps) {
|
||||
return (
|
||||
<Card className="items-center !px-3">
|
||||
<Icon weight="fill" className="w-6 h-6 mr-3 text-ink-dull opacity-20" />
|
||||
<Icon weight="fill" className="mr-3 h-6 w-6 text-ink-dull opacity-20" />
|
||||
<div>
|
||||
<h2 className="text-sm font-medium">{category}</h2>
|
||||
<p className="text-xs text-ink-faint">23,324 items</p>
|
||||
|
||||
@@ -12,8 +12,12 @@ export default ({ mini, ...props }: PropsWithChildren<Props>) => {
|
||||
return (
|
||||
<div className="flex flex-row">
|
||||
<div className={clsx('flex w-full flex-col', !mini && 'pb-6', props.className)}>
|
||||
<h3 className="mb-1 text-sm font-medium text-gray-700 dark:text-gray-100">{props.title}</h3>
|
||||
{!!props.description && <p className="mb-2 text-sm text-gray-400 ">{props.description}</p>}
|
||||
<h3 className="mb-1 text-sm font-medium text-gray-700 dark:text-gray-100">
|
||||
{props.title}
|
||||
</h3>
|
||||
{!!props.description && (
|
||||
<p className="mb-2 text-sm text-gray-400 ">{props.description}</p>
|
||||
)}
|
||||
{!mini && props.children}
|
||||
</div>
|
||||
{mini && props.children}
|
||||
|
||||
@@ -15,7 +15,10 @@ export const Component = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<Heading title="General Settings" description="General settings related to this client." />
|
||||
<Heading
|
||||
title="General Settings"
|
||||
description="General settings related to this client."
|
||||
/>
|
||||
<Card className="px-5">
|
||||
<div className="my-2 flex w-full flex-col">
|
||||
<div className="flex flex-row items-center justify-between">
|
||||
@@ -50,7 +53,9 @@ export const Component = () => {
|
||||
</div>
|
||||
<div className="mt-5 flex items-center space-x-3">
|
||||
<Switch size="sm" checked />
|
||||
<span className="text-sm font-medium text-ink-dull">Run daemon when app closed</span>
|
||||
<span className="text-sm font-medium text-ink-dull">
|
||||
Run daemon when app closed
|
||||
</span>
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<div
|
||||
|
||||
@@ -73,7 +73,9 @@ export default (props: UseDialogProps) => {
|
||||
className="mt-3 mb-2"
|
||||
right={
|
||||
<Button
|
||||
onClick={() => setShow((old) => ({ ...old, masterPassword: !old.masterPassword }))}
|
||||
onClick={() =>
|
||||
setShow((old) => ({ ...old, masterPassword: !old.masterPassword }))
|
||||
}
|
||||
size="icon"
|
||||
type="button"
|
||||
>
|
||||
|
||||
@@ -77,7 +77,9 @@ export default (props: UseDialogProps) => {
|
||||
setKey(e);
|
||||
}}
|
||||
>
|
||||
{keys.data && <KeyListSelectOptions keys={keys.data.map((key) => key.uuid)} />}
|
||||
{keys.data && (
|
||||
<KeyListSelectOptions keys={keys.data.map((key) => key.uuid)} />
|
||||
)}
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -96,13 +98,24 @@ export default (props: UseDialogProps) => {
|
||||
</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-xs font-bold">Hashing</span>
|
||||
<Select className="mt-2 text-gray-300" value={hashingAlgo} disabled onChange={() => {}}>
|
||||
<Select
|
||||
className="mt-2 text-gray-300"
|
||||
value={hashingAlgo}
|
||||
disabled
|
||||
onChange={() => {}}
|
||||
>
|
||||
<SelectOption value="Argon2id-s">Argon2id (standard)</SelectOption>
|
||||
<SelectOption value="Argon2id-h">Argon2id (hardened)</SelectOption>
|
||||
<SelectOption value="Argon2id-p">Argon2id (paranoid)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-s">BLAKE3-Balloon (standard)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-h">BLAKE3-Balloon (hardened)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-p">BLAKE3-Balloon (paranoid)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-s">
|
||||
BLAKE3-Balloon (standard)
|
||||
</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-h">
|
||||
BLAKE3-Balloon (hardened)
|
||||
</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-p">
|
||||
BLAKE3-Balloon (paranoid)
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -110,14 +110,18 @@ export default (props: UseDialogProps) => {
|
||||
<Button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(form.watch('masterPassword') as string);
|
||||
navigator.clipboard.writeText(
|
||||
form.watch('masterPassword') as string
|
||||
);
|
||||
}}
|
||||
size="icon"
|
||||
>
|
||||
<Clipboard className="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => setShow((old) => ({ ...old, masterPassword: !old.masterPassword }))}
|
||||
onClick={() =>
|
||||
setShow((old) => ({ ...old, masterPassword: !old.masterPassword }))
|
||||
}
|
||||
size="icon"
|
||||
type="button"
|
||||
>
|
||||
@@ -134,7 +138,9 @@ export default (props: UseDialogProps) => {
|
||||
{...form.register('masterPassword2', { required: true })}
|
||||
right={
|
||||
<Button
|
||||
onClick={() => setShow((old) => ({ ...old, masterPassword2: !old.masterPassword2 }))}
|
||||
onClick={() =>
|
||||
setShow((old) => ({ ...old, masterPassword2: !old.masterPassword2 }))
|
||||
}
|
||||
size="icon"
|
||||
type="button"
|
||||
>
|
||||
@@ -167,9 +173,15 @@ export default (props: UseDialogProps) => {
|
||||
<SelectOption value="Argon2id-s">Argon2id (standard)</SelectOption>
|
||||
<SelectOption value="Argon2id-h">Argon2id (hardened)</SelectOption>
|
||||
<SelectOption value="Argon2id-p">Argon2id (paranoid)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-s">BLAKE3-Balloon (standard)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-h">BLAKE3-Balloon (hardened)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-p">BLAKE3-Balloon (paranoid)</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-s">
|
||||
BLAKE3-Balloon (standard)
|
||||
</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-h">
|
||||
BLAKE3-Balloon (hardened)
|
||||
</SelectOption>
|
||||
<SelectOption value="BalloonBlake3-p">
|
||||
BLAKE3-Balloon (paranoid)
|
||||
</SelectOption>
|
||||
</Select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -130,7 +130,10 @@ export const Component = () => {
|
||||
if (masterPassword !== '') {
|
||||
setMasterPassword('');
|
||||
setSecretKey('');
|
||||
unlockKeyManager.mutate({ password: masterPassword, secret_key: secretKey });
|
||||
unlockKeyManager.mutate({
|
||||
password: masterPassword,
|
||||
secret_key: secretKey
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
@@ -188,7 +191,11 @@ export const Component = () => {
|
||||
<Subheading title="Secret key" />
|
||||
{!viewSecretKey && (
|
||||
<div className="flex flex-row">
|
||||
<Button size="sm" variant="gray" onClick={() => setViewSecretKey(true)}>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="gray"
|
||||
onClick={() => setViewSecretKey(true)}
|
||||
>
|
||||
View Secret Key
|
||||
</Button>
|
||||
</div>
|
||||
@@ -215,7 +222,9 @@ export const Component = () => {
|
||||
size="sm"
|
||||
variant="gray"
|
||||
className="mr-2"
|
||||
onClick={() => dialogManager.create((dp) => <MasterPasswordDialog {...dp} />)}
|
||||
onClick={() =>
|
||||
dialogManager.create((dp) => <MasterPasswordDialog {...dp} />)
|
||||
}
|
||||
>
|
||||
Change Master Password
|
||||
</Button>
|
||||
@@ -257,7 +266,9 @@ export const Component = () => {
|
||||
size="sm"
|
||||
variant="gray"
|
||||
className="mr-2"
|
||||
onClick={() => dialogManager.create((dp) => <BackupRestoreDialog {...dp} />)}
|
||||
onClick={() =>
|
||||
dialogManager.create((dp) => <BackupRestoreDialog {...dp} />)
|
||||
}
|
||||
>
|
||||
Restore
|
||||
</Button>
|
||||
|
||||
@@ -122,8 +122,8 @@ export const Component = () => {
|
||||
<FlexCol>
|
||||
<Input label="Display Name" {...form.register('name')} />
|
||||
<InfoText>
|
||||
The name of this Location, this is what will be displayed in the sidebar. Will not
|
||||
rename the actual folder on disk.
|
||||
The name of this Location, this is what will be displayed in the
|
||||
sidebar. Will not rename the actual folder on disk.
|
||||
</InfoText>
|
||||
</FlexCol>
|
||||
<FlexCol>
|
||||
@@ -134,7 +134,8 @@ export const Component = () => {
|
||||
{...form.register('path')}
|
||||
/>
|
||||
<InfoText>
|
||||
The path to this Location, this is where the files will be stored on disk.
|
||||
The path to this Location, this is where the files will be stored on
|
||||
disk.
|
||||
</InfoText>
|
||||
</FlexCol>
|
||||
</div>
|
||||
@@ -145,7 +146,9 @@ export const Component = () => {
|
||||
<Switch {...form.register('generatePreviewMedia')} size="sm" />
|
||||
</ToggleSection>
|
||||
<ToggleSection>
|
||||
<Label className="grow">Sync preview media for this Location with your devices</Label>
|
||||
<Label className="grow">
|
||||
Sync preview media for this Location with your devices
|
||||
</Label>
|
||||
<Switch {...form.register('syncPreviewMedia')} size="sm" />
|
||||
</ToggleSection>
|
||||
<ToggleSection>
|
||||
@@ -174,7 +177,11 @@ export const Component = () => {
|
||||
<div className="flex space-x-5">
|
||||
<FlexCol>
|
||||
<div>
|
||||
<Button onClick={() => fullRescan.mutate(locationId)} size="sm" variant="outline">
|
||||
<Button
|
||||
onClick={() => fullRescan.mutate(locationId)}
|
||||
size="sm"
|
||||
variant="outline"
|
||||
>
|
||||
<ArrowsClockwise className="mr-1.5 -mt-0.5 inline h-4 w-4" />
|
||||
Full Reindex
|
||||
</Button>
|
||||
@@ -194,12 +201,17 @@ export const Component = () => {
|
||||
</Button>
|
||||
</div>
|
||||
<InfoText>
|
||||
Extract data from Library as an archive, useful to preserve Location folder structure.
|
||||
Extract data from Library as an archive, useful to preserve Location
|
||||
folder structure.
|
||||
</InfoText>
|
||||
</FlexCol>
|
||||
<FlexCol>
|
||||
<div>
|
||||
<Button size="sm" variant="colored" className="border-red-500 bg-red-500">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="colored"
|
||||
className="border-red-500 bg-red-500"
|
||||
>
|
||||
<Trash className="mr-1.5 -mt-0.5 inline h-4 w-4" />
|
||||
Delete
|
||||
</Button>
|
||||
|
||||
@@ -16,7 +16,9 @@ export const AddLocationButton = ({ className, ...props }: ButtonProps) => {
|
||||
openDirectoryPickerDialog(platform)
|
||||
.then((path) => {
|
||||
if (path !== '')
|
||||
dialogManager.create((dp) => <AddLocationDialog path={path ?? ''} {...dp} />);
|
||||
dialogManager.create((dp) => (
|
||||
<AddLocationDialog path={path ?? ''} {...dp} />
|
||||
));
|
||||
})
|
||||
.catch((error) => showAlertDialog({ title: 'Error', value: String(error) }))
|
||||
}
|
||||
|
||||
@@ -85,7 +85,10 @@ export const AddLocationDialog = (props: Props) => {
|
||||
// });
|
||||
break;
|
||||
case 'ADD_LIBRARY':
|
||||
await addLocationToLibrary.mutateAsync({ path, indexer_rules_ids: indexerRulesIds });
|
||||
await addLocationToLibrary.mutateAsync({
|
||||
path,
|
||||
indexer_rules_ids: indexerRulesIds
|
||||
});
|
||||
break;
|
||||
default:
|
||||
throw new Error('Unimplemented custom remote error handling');
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user