mirror of
https://github.com/spacedriveapp/spacedrive
synced 2024-07-02 08:53:32 +00: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:
parent
3e0ac9372b
commit
03eb27e91d
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'"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,7 +7,7 @@
|
|||
"build": "vite build",
|
||||
"server": "ts-node ./server",
|
||||
"server:prod": "cross-env NODE_ENV=production ts-node ./server",
|
||||
"lint": "eslint src",
|
||||
"lint": "eslint src server --cache",
|
||||
"typecheck": "tsc -b"
|
||||
},
|
||||
"dependencies": {
|
||||
|
|
7
apps/landing/server/.eslintrc.js
Normal file
7
apps/landing/server/.eslintrc.js
Normal file
|
@ -0,0 +1,7 @@
|
|||
module.exports = {
|
||||
extends: [require.resolve('@sd/config/eslint/base.js')],
|
||||
parserOptions: {
|
||||
tsconfigRootDir: __dirname,
|
||||
project: './tsconfig.json'
|
||||
}
|
||||
};
|
|
@ -79,7 +79,9 @@ const AppEmbed = () => {
|
|||
referrerPolicy="origin-when-cross-origin"
|
||||
className={clsx(
|
||||
'shadow-iframe inset-center z-30 h-full w-full rounded-lg bg-gray-850',
|
||||
iFrameAppReady ? 'fade-in-app-embed opacity-100' : 'ml-[-10000px] opacity-0'
|
||||
iFrameAppReady
|
||||
? 'fade-in-app-embed opacity-100'
|
||||
: 'ml-[-10000px] opacity-0'
|
||||
)}
|
||||
src={`${
|
||||
import.meta.env.VITE_SDWEB_BASE_URL || 'http://localhost:8002'
|
||||
|
@ -87,7 +89,9 @@ const AppEmbed = () => {
|
|||
/>
|
||||
)}
|
||||
|
||||
{renderImage && <div className="fade-in-app-embed landing-img z-40 h-full w-auto" />}
|
||||
{renderImage && (
|
||||
<div className="fade-in-app-embed landing-img z-40 h-full w-auto" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -59,6 +59,11 @@ export const Bubbles = () => {
|
|||
);
|
||||
|
||||
return (
|
||||
<Particles id="tsparticles" className="absolute z-0" init={particlesInit} options={options} />
|
||||
<Particles
|
||||
id="tsparticles"
|
||||
className="absolute z-0"
|
||||
init={particlesInit}
|
||||
options={options}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -42,7 +42,10 @@ export default function DocsLayout(props: Props) {
|
|||
<div className="flex w-full flex-col sm:flex-row" id="page-container">
|
||||
<div className="mt-[65px] flex h-12 w-full items-center border-y border-gray-600 px-5 sm:hidden">
|
||||
<div className="flex sm:hidden">
|
||||
<Button onClick={() => setMenuOpen(!menuOpen)} className="ml-1 !border-none !px-2">
|
||||
<Button
|
||||
onClick={() => setMenuOpen(!menuOpen)}
|
||||
className="ml-1 !border-none !px-2"
|
||||
>
|
||||
<List weight="bold" className="h-6 w-6" />
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
@ -38,7 +38,11 @@ export default function DocsSidebar(props: Props) {
|
|||
isActive && 'nav-active'
|
||||
)}
|
||||
>
|
||||
<div className={clsx(`mr-4 rounded-lg border-t border-gray-400/20 bg-gray-500 p-1`)}>
|
||||
<div
|
||||
className={clsx(
|
||||
`mr-4 rounded-lg border-t border-gray-400/20 bg-gray-500 p-1`
|
||||
)}
|
||||
>
|
||||
<Icon weight="bold" className="h-4 w-4 text-white opacity-80" />
|
||||
</div>
|
||||
{section.title}
|
||||
|
|
|
@ -76,7 +76,10 @@ export function Footer() {
|
|||
</div>
|
||||
<div className="col-span-1 flex flex-col space-y-2">
|
||||
<h3 className="mb-1 text-xs font-bold uppercase ">Developers</h3>
|
||||
<FooterLink blank link="https://github.com/spacedriveapp/spacedrive/tree/main/docs">
|
||||
<FooterLink
|
||||
blank
|
||||
link="https://github.com/spacedriveapp/spacedrive/tree/main/docs"
|
||||
>
|
||||
Documentation
|
||||
</FooterLink>
|
||||
<FooterLink
|
||||
|
@ -97,7 +100,10 @@ export function Footer() {
|
|||
<FooterLink blank link="https://opencollective.com/spacedrive">
|
||||
Open Collective
|
||||
</FooterLink>
|
||||
<FooterLink blank link="https://github.com/spacedriveapp/spacedrive/blob/main/LICENSE">
|
||||
<FooterLink
|
||||
blank
|
||||
link="https://github.com/spacedriveapp/spacedrive/blob/main/LICENSE"
|
||||
>
|
||||
License
|
||||
</FooterLink>
|
||||
<div>
|
||||
|
|
|
@ -107,7 +107,8 @@ export function HomeCTA() {
|
|||
{(waitlistError || waitlistSubmitted) && (
|
||||
<div
|
||||
className={clsx({
|
||||
'my-2 flex flex-row items-center rounded-md border-2 px-2': true,
|
||||
'my-2 flex flex-row items-center rounded-md border-2 px-2':
|
||||
true,
|
||||
'border-red-900 bg-red-800/20': waitlistError,
|
||||
'border-green-900 bg-green-800/20': !waitlistError,
|
||||
'-mt-2': waitlistSubmitted
|
||||
|
@ -146,9 +147,12 @@ export function HomeCTA() {
|
|||
{!waitlistSubmitted && (
|
||||
<Button
|
||||
onClick={() => setShowWaitlistInput(true)}
|
||||
className={clsx('z-30 cursor-pointer rounded-l-none border-0', {
|
||||
'cursor-default opacity-50': loading
|
||||
})}
|
||||
className={clsx(
|
||||
'z-30 cursor-pointer rounded-l-none border-0',
|
||||
{
|
||||
'cursor-default opacity-50': loading
|
||||
}
|
||||
)}
|
||||
disabled={loading}
|
||||
variant="accent"
|
||||
type="submit"
|
||||
|
@ -166,10 +170,13 @@ export function HomeCTA() {
|
|||
)}
|
||||
</div>
|
||||
<p
|
||||
className={clsx('animation-delay-3 z-30 px-6 text-center text-sm text-gray-450 fade-in', {
|
||||
'mt-10': waitlistError,
|
||||
'mt-3': !waitlistError
|
||||
})}
|
||||
className={clsx(
|
||||
'animation-delay-3 z-30 px-6 text-center text-sm text-gray-450 fade-in',
|
||||
{
|
||||
'mt-10': waitlistError,
|
||||
'mt-3': !waitlistError
|
||||
}
|
||||
)}
|
||||
>
|
||||
{showWaitlistInput ? (
|
||||
<>
|
||||
|
|
|
@ -98,7 +98,10 @@ export default function NavBar() {
|
|||
>
|
||||
Repository
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item icon={Discord} onClick={redirect('https://discord.gg/gTaF2Z44f5')}>
|
||||
<Dropdown.Item
|
||||
icon={Discord}
|
||||
onClick={redirect('https://discord.gg/gTaF2Z44f5')}
|
||||
>
|
||||
Join Discord
|
||||
</Dropdown.Item>
|
||||
</Dropdown.Section>
|
||||
|
@ -106,7 +109,10 @@ export default function NavBar() {
|
|||
<Dropdown.Item icon={MapPin} {...link('/roadmap')}>
|
||||
Roadmap
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item icon={Book} {...link('/docs/product/getting-started/introduction')}>
|
||||
<Dropdown.Item
|
||||
icon={Book}
|
||||
{...link('/docs/product/getting-started/introduction')}
|
||||
>
|
||||
Docs
|
||||
</Dropdown.Item>
|
||||
<Dropdown.Item icon={User} {...link('/team')}>
|
||||
|
@ -130,7 +136,11 @@ export default function NavBar() {
|
|||
<a href="https://discord.gg/gTaF2Z44f5" target="_blank" rel="noreferrer">
|
||||
<Discord className="text-white" />
|
||||
</a>
|
||||
<a href="https://github.com/spacedriveapp/spacedrive" target="_blank" rel="noreferrer">
|
||||
<a
|
||||
href="https://github.com/spacedriveapp/spacedrive"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
<Github className="text-white" />
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -36,7 +36,8 @@ function Page({ posts }: { posts: BlogPosts }) {
|
|||
<small className="m-0">{post.readTime} minute read.</small>
|
||||
{/* <p className="line-clamp-3 my-2">{post.excerpt}</p> */}
|
||||
<p className="m-0 text-white">
|
||||
by {post.author} · {new Date(post.date ?? '').toLocaleDateString()}
|
||||
by {post.author} ·{' '}
|
||||
{new Date(post.date ?? '').toLocaleDateString()}
|
||||
</p>
|
||||
<div className="mt-4 flex flex-wrap gap-2">
|
||||
{post.tags?.map((tag) => (
|
||||
|
|
|
@ -41,7 +41,8 @@ function Page({ post }: { post: BlogPost }) {
|
|||
{post?.title}
|
||||
</h1>
|
||||
<p className="m-0 mt-2">
|
||||
by <b>{post?.author}</b> · {new Date(post?.date ?? '').toLocaleDateString()}
|
||||
by <b>{post?.author}</b> ·{' '}
|
||||
{new Date(post?.date ?? '').toLocaleDateString()}
|
||||
</p>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
|
|
|
@ -86,13 +86,17 @@ const perks = [
|
|||
|
||||
function Page() {
|
||||
const openPositionsRef = useRef<HTMLHRElement>(null);
|
||||
const scrollToPositions = () => openPositionsRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
const scrollToPositions = () =>
|
||||
openPositionsRef.current?.scrollIntoView({ behavior: 'smooth' });
|
||||
|
||||
return (
|
||||
<>
|
||||
<Helmet>
|
||||
<title>Careers - Spacedrive</title>
|
||||
<meta name="description" content="Work with us to build the future of file management." />
|
||||
<meta
|
||||
name="description"
|
||||
content="Work with us to build the future of file management."
|
||||
/>
|
||||
</Helmet>
|
||||
<div className="prose prose-invert container relative m-auto mb-20 min-h-screen max-w-4xl p-4 pt-32 text-white">
|
||||
<div
|
||||
|
@ -104,9 +108,9 @@ function Page() {
|
|||
</h1>
|
||||
<div className="animation-delay-1 z-30 flex flex-col items-center fade-in">
|
||||
<p className="z-40 text-center text-lg text-gray-350">
|
||||
Spacedrive is redefining the way we think about our personal data, building a open
|
||||
ecosystem to help preserve your digital legacy and make cross-platform file management a
|
||||
breeze.
|
||||
Spacedrive is redefining the way we think about our personal data, building
|
||||
a open ecosystem to help preserve your digital legacy and make
|
||||
cross-platform file management a breeze.
|
||||
</p>
|
||||
<Button
|
||||
onClick={scrollToPositions}
|
||||
|
@ -116,7 +120,9 @@ function Page() {
|
|||
See Open Positions
|
||||
</Button>
|
||||
<hr className="border-1 my-24 w-full border-gray-200 opacity-10" />
|
||||
<h2 className="mb-0 px-2 text-center text-4xl font-black leading-tight">Our Values</h2>
|
||||
<h2 className="mb-0 px-2 text-center text-4xl font-black leading-tight">
|
||||
Our Values
|
||||
</h2>
|
||||
<p className="mt-2 mb-4">What drives us daily.</p>
|
||||
<div className="mt-5 grid w-full grid-cols-1 gap-4 sm:grid-cols-2">
|
||||
{values.map((value, index) => (
|
||||
|
@ -125,7 +131,9 @@ function Page() {
|
|||
className="flex flex-col rounded-md border border-gray-500 bg-gray-550/50 p-10"
|
||||
>
|
||||
<value.icon className="text-[32px]" weight="bold" />
|
||||
<h3 className="mt-4 mb-1 text-2xl font-bold leading-snug">{value.title}</h3>
|
||||
<h3 className="mt-4 mb-1 text-2xl font-bold leading-snug">
|
||||
{value.title}
|
||||
</h3>
|
||||
<p className="mt-1 mb-0 text-gray-350">{value.desc}</p>
|
||||
</div>
|
||||
))}
|
||||
|
@ -139,16 +147,28 @@ function Page() {
|
|||
{perks.map((value, index) => (
|
||||
<div
|
||||
key={value.title + index}
|
||||
style={{ backgroundColor: value.color + '10', borderColor: value.color + '30' }}
|
||||
style={{
|
||||
backgroundColor: value.color + '10',
|
||||
borderColor: value.color + '30'
|
||||
}}
|
||||
className="flex flex-col rounded-md border bg-gray-550/30 p-8"
|
||||
>
|
||||
<value.icon className="text-[32px]" weight="bold" color={value.color} />
|
||||
<value.icon
|
||||
className="text-[32px]"
|
||||
weight="bold"
|
||||
color={value.color}
|
||||
/>
|
||||
<h3 className="mt-4 mb-1">{value.title}</h3>
|
||||
<p className="mt-1 mb-0 text-sm text-white opacity-60">{value.desc}</p>
|
||||
<p className="mt-1 mb-0 text-sm text-white opacity-60">
|
||||
{value.desc}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<hr className="border-1 my-24 w-full border-gray-200 opacity-10" ref={openPositionsRef} />
|
||||
<hr
|
||||
className="border-1 my-24 w-full border-gray-200 opacity-10"
|
||||
ref={openPositionsRef}
|
||||
/>
|
||||
<h2 className="mb-0 px-2 text-center text-4xl font-black leading-tight text-white">
|
||||
Open Positions
|
||||
</h2>
|
||||
|
@ -183,10 +203,13 @@ function Page() {
|
|||
)}
|
||||
</div>
|
||||
<hr className="border-1 my-24 w-full border-gray-200 opacity-10" />
|
||||
<h2 className="mb-0 px-2 text-center text-3xl font-black text-white">How to apply?</h2>
|
||||
<h2 className="mb-0 px-2 text-center text-3xl font-black text-white">
|
||||
How to apply?
|
||||
</h2>
|
||||
<p className="mt-2">
|
||||
Send your cover letter and resume to <strong>careers at spacedrive dot com</strong> and
|
||||
we'll get back to you shortly!
|
||||
Send your cover letter and resume to{' '}
|
||||
<strong>careers at spacedrive dot com</strong> and we'll get back to you
|
||||
shortly!
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -21,7 +21,9 @@ export async function prerender() {
|
|||
|
||||
const docsArray = Object.keys(docs).map((url) => ({
|
||||
url: `/docs/${url}/`,
|
||||
pageContext: { pageProps: { doc: docs[url], navigation, nextDoc: getNextDoc(navigation, url) } }
|
||||
pageContext: {
|
||||
pageProps: { doc: docs[url], navigation, nextDoc: getNextDoc(navigation, url) }
|
||||
}
|
||||
}));
|
||||
|
||||
return [
|
||||
|
|
|
@ -16,8 +16,8 @@ function Page({ navigation }: { navigation: DocsNavigation }) {
|
|||
<div className="mt-[105px]">
|
||||
<h1 className="text-4xl font-bold">Spacedrive Docs</h1>
|
||||
<p className="text-lg text-gray-400">
|
||||
Welcome to the Spacedrive documentation. Here you can find all the information you
|
||||
need to get started with Spacedrive.
|
||||
Welcome to the Spacedrive documentation. Here you can find all the
|
||||
information you need to get started with Spacedrive.
|
||||
</p>
|
||||
<a
|
||||
className="text-primary-600 transition hover:text-primary-500"
|
||||
|
|
|
@ -112,7 +112,9 @@ function Page() {
|
|||
}
|
||||
>
|
||||
<Info className="mr-1 w-5 fill-green-500" />
|
||||
<p className={'text-sm text-green-500'}>You have been unsubscribed from the waitlist</p>
|
||||
<p className={'text-sm text-green-500'}>
|
||||
You have been unsubscribed from the waitlist
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
@ -120,8 +122,8 @@ function Page() {
|
|||
A file explorer from the future.
|
||||
</h1>
|
||||
<p className="animation-delay-1 fade-in-heading text-md leading-2 z-30 mt-1 mb-8 max-w-4xl text-center text-gray-450 lg:text-lg lg:leading-8">
|
||||
Combine your drives and clouds into one database that you can organize and explore from any
|
||||
device.
|
||||
Combine your drives and clouds into one database that you can organize and explore
|
||||
from any device.
|
||||
<br />
|
||||
<span className="hidden sm:block">
|
||||
Designed for creators, hoarders and the painfully disorganized.
|
||||
|
@ -135,9 +137,9 @@ function Page() {
|
|||
className="z-30 mt-0 sm:mt-8"
|
||||
description={
|
||||
<>
|
||||
Spacedrive accounts for every file you own, uniquely fingerprinting and extracting
|
||||
metadata so you can sort, tag, backup and share files without limitations of any one
|
||||
cloud provider.
|
||||
Spacedrive accounts for every file you own, uniquely fingerprinting and
|
||||
extracting metadata so you can sort, tag, backup and share files without
|
||||
limitations of any one cloud provider.
|
||||
<br />
|
||||
<br />
|
||||
<a
|
||||
|
|
|
@ -60,7 +60,8 @@ function Page() {
|
|||
},
|
||||
{
|
||||
title: 'Search',
|
||||
description: 'Deep search into your filesystem with a keybind, including offline locations.'
|
||||
description:
|
||||
'Deep search into your filesystem with a keybind, including offline locations.'
|
||||
},
|
||||
{
|
||||
title: 'Photos',
|
||||
|
@ -84,7 +85,8 @@ function Page() {
|
|||
},
|
||||
{
|
||||
title: 'Hosted Spaces',
|
||||
description: 'Host select Spaces on our cloud to share with friends or publish on the web.'
|
||||
description:
|
||||
'Host select Spaces on our cloud to share with friends or publish on the web.'
|
||||
},
|
||||
{
|
||||
when: '0.6.0 Beta',
|
||||
|
@ -130,7 +132,8 @@ function Page() {
|
|||
What's next for Spacedrive?
|
||||
</h1>
|
||||
<p className="animation-delay-2 fade-in-heading text-center text-gray-400">
|
||||
Here is a list of the features we are working on, and the progress we have made so far.
|
||||
Here is a list of the features we are working on, and the progress we have
|
||||
made so far.
|
||||
</p>
|
||||
</section>
|
||||
<section className="grid auto-cols-auto grid-flow-row grid-cols-[auto_1fr] gap-x-4">
|
||||
|
@ -147,7 +150,11 @@ function Page() {
|
|||
>
|
||||
{item.when}
|
||||
</h3>
|
||||
{item?.subtext && <span className="text-sm text-gray-300">{item?.subtext}</span>}
|
||||
{item?.subtext && (
|
||||
<span className="text-sm text-gray-300">
|
||||
{item?.subtext}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="flex h-full w-2 group-first:mt-2 group-first:rounded-t-full group-last-of-type:rounded-b-full lg:items-center">
|
||||
<div
|
||||
|
@ -160,7 +167,9 @@ function Page() {
|
|||
<div
|
||||
className={clsx(
|
||||
'absolute z-20 mt-5 h-4 w-4 -translate-y-1/2 -translate-x-1/4 rounded-full border-2 border-gray-200 group-first:mt-0 group-first:self-start lg:mt-0',
|
||||
items[i - 1]?.completed || i === 0 ? 'z-10 bg-primary-500' : 'bg-gray-550'
|
||||
items[i - 1]?.completed || i === 0
|
||||
? 'z-10 bg-primary-500'
|
||||
: 'bg-gray-550'
|
||||
)}
|
||||
>
|
||||
‍
|
||||
|
@ -173,7 +182,9 @@ function Page() {
|
|||
</span>
|
||||
<div className="group flex flex-col items-start justify-center gap-4">
|
||||
{item?.when && (
|
||||
<h3 className="mb-0 group-first-of-type:m-0 lg:hidden">{item.when}</h3>
|
||||
<h3 className="mb-0 group-first-of-type:m-0 lg:hidden">
|
||||
{item.when}
|
||||
</h3>
|
||||
)}
|
||||
<div className="my-2 flex w-full flex-col space-y-2 rounded-xl border border-gray-500 p-4 group-last:mb-0 group-first-of-type:mt-0">
|
||||
<h3 className="m-0">{item.title}</h3>
|
||||
|
@ -187,8 +198,9 @@ function Page() {
|
|||
<h2 className="my-1">That's not all.</h2>
|
||||
<p>
|
||||
We're always open to ideas and feedback over{' '}
|
||||
<a href="https://github.com/spacedriveapp/spacedrive/discussions">here</a> and we have a{' '}
|
||||
<a href="/blog">blog</a> where you can find the latest news and updates.
|
||||
<a href="https://github.com/spacedriveapp/spacedrive/discussions">here</a>{' '}
|
||||
and we have a <a href="/blog">blog</a> where you can find the latest news
|
||||
and updates.
|
||||
</p>
|
||||
</section>
|
||||
</div>
|
||||
|
|
|
@ -199,16 +199,17 @@ function Page() {
|
|||
/>
|
||||
<div className="relative z-10">
|
||||
<h1 className="fade-in-heading text-5xl leading-tight sm:leading-snug ">
|
||||
We believe file management should be <span className="title-gradient">universal</span>.
|
||||
We believe file management should be{' '}
|
||||
<span className="title-gradient">universal</span>.
|
||||
</h1>
|
||||
<p className="animation-delay-2 fade-in-heading text-white/50 ">
|
||||
Your priceless personal data shouldn't be stuck in a device ecosystem. It should be OS
|
||||
agnostic, permanent and owned by you.
|
||||
Your priceless personal data shouldn't be stuck in a device ecosystem. It
|
||||
should be OS agnostic, permanent and owned by you.
|
||||
</p>
|
||||
<p className="animation-delay-2 fade-in-heading text-white/50 ">
|
||||
The data we create daily is our legacy—that will long outlive us. Open source technology
|
||||
is the only way to ensure we retain absolute control over the files that define our
|
||||
lives, at unlimited scale.
|
||||
The data we create daily is our legacy—that will long outlive us. Open
|
||||
source technology is the only way to ensure we retain absolute control over
|
||||
the files that define our lives, at unlimited scale.
|
||||
</p>
|
||||
<a
|
||||
href="/docs/product/resources/faq"
|
||||
|
@ -236,7 +237,10 @@ function Page() {
|
|||
</a>{' '}
|
||||
on GitHub.
|
||||
</p>
|
||||
<h2 id="investors" className="mt-10 mb-2 text-2xl leading-relaxed sm:mt-20 ">
|
||||
<h2
|
||||
id="investors"
|
||||
className="mt-10 mb-2 text-2xl leading-relaxed sm:mt-20 "
|
||||
>
|
||||
Our investors
|
||||
</h2>
|
||||
<p className="text-sm text-gray-400 ">
|
||||
|
@ -244,7 +248,10 @@ function Page() {
|
|||
</p>
|
||||
<div className="my-10 grid grid-cols-3 gap-x-5 gap-y-10 sm:grid-cols-5">
|
||||
{investors.map((investor) => (
|
||||
<TeamMember key={investor.name + investor.investmentRound} {...investor} />
|
||||
<TeamMember
|
||||
key={investor.name + investor.investmentRound}
|
||||
{...investor}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -16,7 +16,9 @@ function Page({ is404 }: { is404: boolean }) {
|
|||
<div className="m-auto flex flex-col items-center ">
|
||||
<div className="h-32" />
|
||||
<SmileyXEyes className="mb-3 h-44 w-44" />
|
||||
<h1 className="mb-2 text-center">In the quantum realm this page potentially exists.</h1>
|
||||
<h1 className="mb-2 text-center">
|
||||
In the quantum realm this page potentially exists.
|
||||
</h1>
|
||||
<p>In other words, thats a 404.</p>
|
||||
<div className="flex flex-wrap justify-center">
|
||||
<Button
|
||||
|
@ -26,7 +28,11 @@ function Page({ is404 }: { is404: boolean }) {
|
|||
>
|
||||
← Back
|
||||
</Button>
|
||||
<Button href="/" className="mt-2 cursor-pointer !text-white" variant="accent">
|
||||
<Button
|
||||
href="/"
|
||||
className="mt-2 cursor-pointer !text-white"
|
||||
variant="accent"
|
||||
>
|
||||
Discover Spacedrive →
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
@ -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>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue