[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:
Vítor Vasconcellos 2023-04-14 21:21:21 +00:00 committed by GitHub
parent 3e0ac9372b
commit 03eb27e91d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
162 changed files with 2030 additions and 1162 deletions

56
.editorconfig Normal file
View 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
View file

@ -0,0 +1,2 @@
pnpm-lock.yaml -diff
package-lock.json -diff

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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"
},

View file

@ -0,0 +1,7 @@
module.exports = {
extends: [require.resolve('@sd/config/eslint/web.js')],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
};

View file

@ -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",

View file

@ -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) => {

View file

@ -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,

View file

@ -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'"
}
}
}

View file

@ -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": {

View file

@ -0,0 +1,7 @@
module.exports = {
extends: [require.resolve('@sd/config/eslint/base.js')],
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
}
};

View file

@ -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>

View file

@ -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}
/>
);
};

View file

@ -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>

View file

@ -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}

View file

@ -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>

View file

@ -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 ? (
<>

View file

@ -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>

View file

@ -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} &middot; {new Date(post.date ?? '').toLocaleDateString()}
by {post.author} &middot;{' '}
{new Date(post.date ?? '').toLocaleDateString()}
</p>
<div className="mt-4 flex flex-wrap gap-2">
{post.tags?.map((tag) => (

View file

@ -41,7 +41,8 @@ function Page({ post }: { post: BlogPost }) {
{post?.title}
</h1>
<p className="m-0 mt-2">
by <b>{post?.author}</b> &middot; {new Date(post?.date ?? '').toLocaleDateString()}
by <b>{post?.author}</b> &middot;{' '}
{new Date(post?.date ?? '').toLocaleDateString()}
</p>
</div>
<div className="flex flex-wrap gap-2">

View file

@ -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>

View file

@ -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 [

View file

@ -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"

View file

@ -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

View file

@ -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'
)}
>
&zwj;
@ -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>

View file

@ -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 legacythat 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 legacythat 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>

View file

@ -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>

View file

@ -3,5 +3,13 @@ module.exports = {
parserOptions: {
tsconfigRootDir: __dirname,
project: './tsconfig.json'
},
rules: {
'tailwindcss/classnames-order': [
'warn',
{
config: './tailwind.config.js'
}
]
}
};

View file

@ -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 ../"

View file

@ -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>

View file

@ -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;

View file

@ -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 */}

View file

@ -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`} />

View file

@ -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>

View file

@ -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>

View file

@ -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}

View file

@ -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>

View file

@ -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

View file

@ -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>
);
};

View file

@ -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>

View file

@ -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(
{

View file

@ -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}

View file

@ -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>

View file

@ -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>

View file

@ -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}

View file

@ -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>

View file

@ -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 && (

View file

@ -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>
)}

View file

@ -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>
)}

View file

@ -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>
) : (

View file

@ -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: {

View file

@ -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>

View file

@ -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`}
/>

View file

@ -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>
);
}

View file

@ -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>
);
}

View file

@ -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.

View file

@ -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"

View file

@ -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>
);

View file

@ -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>
);

View file

@ -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"

View file

@ -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 && (

View file

@ -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>
);
}

View file

@ -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) {

View file

@ -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`}>
&copy; 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>

View file

@ -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>

View file

@ -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>

View file

@ -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>
);

View file

@ -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}

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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
View 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/**/*']
};

View file

@ -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>

View file

@ -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'
}}
/>

View file

@ -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}

View file

@ -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({

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>) {

View file

@ -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>

View file

@ -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}

View file

@ -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>

View file

@ -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>
}

View file

@ -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

View file

@ -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" />

View file

@ -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

View file

@ -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>

View file

@ -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 && (

View file

@ -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>

View file

@ -49,7 +49,10 @@ export default () => {
if (masterPassword !== '') {
setMasterPassword('');
setSecretKey('');
unlockKeyManager.mutate({ password: masterPassword, secret_key: secretKey });
unlockKeyManager.mutate({
password: masterPassword,
secret_key: secretKey
});
}
}}
>

View file

@ -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} />

View file

@ -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

View file

@ -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

View file

@ -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" />
);
};

View file

@ -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">&#8226;</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