This commit is contained in:
FTCHD
2026-08-30 19:35:20 +03:00
parent c27ce131e6
commit fa3e5ead63
11 changed files with 61 additions and 24 deletions
+1
View File
@@ -32,3 +32,4 @@ scripts/release.md
src-tauri/binaries/* src-tauri/binaries/*
!src-tauri/binaries/.gitkeep !src-tauri/binaries/.gitkeep
/public/out.js /public/out.js
video
+11
View File
@@ -0,0 +1,11 @@
import { type ReactNode, createContext, useContext } from 'react'
const PreviewContext = createContext(false)
export function PreviewProvider({ children }: { children: ReactNode }) {
return <PreviewContext.Provider value={true}>{children}</PreviewContext.Provider>
}
export function useIsPreview(): boolean {
return useContext(PreviewContext)
}
+4 -1
View File
@@ -15,7 +15,10 @@ async function buildExternal() {
// Compile TypeScript using local tsc // Compile TypeScript using local tsc
console.log('[buildExternal] Compiling TypeScript...') console.log('[buildExternal] Compiling TypeScript...')
execSync( execSync(
'npx tsc main.ts --target es2020 --module esnext --moduleResolution bundler --listEmittedFiles', // skipLibCheck mirrors tsconfig.json: a bare-CLI tsc ignores tsconfig and
// auto-includes every node_modules/@types package, and Remotion's transitive
// @types/dom-webcodecs collides with the WebCodecs types TS now bundles in lib.dom.
'npx tsc main.ts --target es2020 --module esnext --moduleResolution bundler --skipLibCheck --listEmittedFiles',
{ {
stdio: 'inherit', stdio: 'inherit',
cwd: projectRoot, cwd: projectRoot,
+3
View File
@@ -17,6 +17,7 @@ import { platform } from '@tauri-apps/plugin-os'
import { ExternalLinkIcon, RefreshCwIcon, SearchCheckIcon, SquareIcon } from 'lucide-react' import { ExternalLinkIcon, RefreshCwIcon, SearchCheckIcon, SquareIcon } from 'lucide-react'
import { useMemo, useState } from 'react' import { useMemo, useState } from 'react'
import { formatBytes } from '../../lib/format' import { formatBytes } from '../../lib/format'
import { useIsPreview } from '../../lib/preview'
import { notify } from '../../lib/notifications' import { notify } from '../../lib/notifications'
import { startBatch } from '../../lib/rclone/api' import { startBatch } from '../../lib/rclone/api'
import rclone from '../../lib/rclone/client' import rclone from '../../lib/rclone/client'
@@ -35,6 +36,7 @@ export default function JobDetailsDrawer({
onSelectJob?: (job: JobItem) => void onSelectJob?: (job: JobItem) => void
}) { }) {
const queryClient = useQueryClient() const queryClient = useQueryClient()
const isPreview = useIsPreview()
const [retryStatus, setRetryStatus] = useState< const [retryStatus, setRetryStatus] = useState<
Map<string, { status: 'pending' | 'started' | 'error'; jobId?: number; error?: string }> Map<string, { status: 'pending' | 'started' | 'error'; jobId?: number; error?: string }>
>(new Map()) >(new Map())
@@ -302,6 +304,7 @@ export default function JobDetailsDrawer({
> >
<Progress <Progress
value={item.percentage} value={item.percentage}
disableAnimation={isPreview}
classNames={{ classNames={{
base: 'overflow-hidden rounded-full max-w-lg', base: 'overflow-hidden rounded-full max-w-lg',
}} }}
+3
View File
@@ -37,6 +37,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Group, Panel, Separator } from 'react-resizable-panels' import { Group, Panel, Separator } from 'react-resizable-panels'
import { onErrorDialog, reportError } from '../../lib/errors' import { onErrorDialog, reportError } from '../../lib/errors'
import { getFsInfo } from '../../lib/format' import { getFsInfo } from '../../lib/format'
import { useIsPreview } from '../../lib/preview'
// import { Document, Page, pdfjs } from 'react-pdf' // import { Document, Page, pdfjs } from 'react-pdf'
import { formatBytes } from '../../lib/format.ts' import { formatBytes } from '../../lib/format.ts'
import { notify } from '../../lib/notifications' import { notify } from '../../lib/notifications'
@@ -524,6 +525,7 @@ function TransferItem({
} }
status: 'transferring' | 'checking' | 'done' | 'error' status: 'transferring' | 'checking' | 'done' | 'error'
}) { }) {
const isPreview = useIsPreview()
const fileName = item.name?.split('/').pop() || item.name || 'Unknown' const fileName = item.name?.split('/').pop() || item.name || 'Unknown'
return ( return (
@@ -562,6 +564,7 @@ function TransferItem({
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
<Progress <Progress
value={item.percentage || 0} value={item.percentage || 0}
disableAnimation={isPreview}
size="sm" size="sm"
color={status === 'checking' ? 'warning' : 'primary'} color={status === 'checking' ? 'warning' : 'primary'}
className="flex-1" className="flex-1"
+2 -3
View File
@@ -275,12 +275,12 @@ export default function Delete() {
{supportsPurge && ( {supportsPurge && (
<Alert <Alert
color="primary" color="primary"
title="LET ME SHARE A TIP" title="LET ME SHARE A TIP!"
variant="faded" variant="faded"
className="min-h-none h-fit max-h-fit" className="min-h-none h-fit max-h-fit"
> >
If you're deleting a entire folder, "{sourceRemoteName}" supports Purge If you're deleting a entire folder, "{sourceRemoteName}" supports Purge
which is more efficient! which is more efficient.
</Alert> </Alert>
)} )}
@@ -303,7 +303,6 @@ export default function Delete() {
buttonText={buttonText} buttonText={buttonText}
buttonIcon={buttonIcon} buttonIcon={buttonIcon}
newLabel="NEW DELETE" newLabel="NEW DELETE"
newButtonPrimary={false}
showViewTransfers={false} showViewTransfers={false}
resetPathsLabel="Reset Path" resetPathsLabel="Reset Path"
onResetPaths={handleResetPaths} onResetPaths={handleResetPaths}
+2 -1
View File
@@ -91,7 +91,7 @@ export default function NotificationsSection() {
/> />
))} ))}
<DummyProviderCard <DummyProviderCard
label="Telegram (bot-less)" label="Telegram (botless)"
description="Get messages without your own bot" description="Get messages without your own bot"
icon={<TelegramIcon className="text-sky-500 size-8 shrink-0" />} icon={<TelegramIcon className="text-sky-500 size-8 shrink-0" />}
onPress={() => onPress={() =>
@@ -166,6 +166,7 @@ function ProviderCard({
onPress={onPress} onPress={onPress}
className="h-24 bg-content2" className="h-24 bg-content2"
data-focus-visible="false" data-focus-visible="false"
data-provider={provider}
> >
<CardBody className="relative flex flex-row items-center gap-3 px-4"> <CardBody className="relative flex flex-row items-center gap-3 px-4">
<ProviderIcon <ProviderIcon
+2 -1
View File
@@ -181,7 +181,7 @@ export default function RemotesSection() {
if (remotes.length === 0 && !creatingDrawerOpen) { if (remotes.length === 0 && !creatingDrawerOpen) {
return withRoot( return withRoot(
<div className="flex flex-col items-center justify-center gap-8"> <div className="flex flex-col items-center justify-center gap-8">
<h1 className="text-2xl font-bold">No remotes found</h1> <h1 className="text-2xl font-bold">Add your first remote!</h1>
<Button <Button
onPress={() => setCreatingDrawerOpen(true)} onPress={() => setCreatingDrawerOpen(true)}
color="primary" color="primary"
@@ -449,6 +449,7 @@ function RemoteCard({
return ( return (
<Card <Card
key={remote} key={remote}
data-remote={remote}
shadow="sm" shadow="sm"
isBlurred={true} isBlurred={true}
className="w-full h-20 border-[0.5px] dark:border-none border-divider bg-content3/50 dark:bg-content2/90" className="w-full h-20 border-[0.5px] dark:border-none border-divider bg-content3/50 dark:bg-content2/90"
+28 -17
View File
@@ -20,6 +20,7 @@ import {
import { useEffect, useMemo, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
import { useSearchParams } from 'react-router-dom' import { useSearchParams } from 'react-router-dom'
import { LOCAL_HOST_ID } from '../../../lib/hosts' import { LOCAL_HOST_ID } from '../../../lib/hosts'
import { useIsPreview } from '../../../lib/preview'
import rclone from '../../../lib/rclone/client' import rclone from '../../../lib/rclone/client'
import { useStore } from '../../../store/memory' import { useStore } from '../../../store/memory'
import { useCurrentHost, usePersistedStore } from '../../../store/persisted' import { useCurrentHost, usePersistedStore } from '../../../store/persisted'
@@ -36,6 +37,7 @@ import RemotesSection from './RemotesSection'
export default function Settings() { export default function Settings() {
const [searchParams] = useSearchParams() const [searchParams] = useSearchParams()
const isPreview = useIsPreview()
const settingsPass = usePersistedStore((state) => state.settingsPass) const settingsPass = usePersistedStore((state) => state.settingsPass)
const currentHost = useCurrentHost() const currentHost = useCurrentHost()
const isRestartingRclone = useStore((state) => state.isRestartingRclone) const isRestartingRclone = useStore((state) => state.isRestartingRclone)
@@ -144,8 +146,10 @@ export default function Settings() {
className="flex-shrink-0 h-screen px-2 py-4 overflow-y-auto border-r w-52 dark:bg-transparent bg-content2 border-divider dark:border-neutral-700" className="flex-shrink-0 h-screen px-2 py-4 overflow-y-auto border-r w-52 dark:bg-transparent bg-content2 border-divider dark:border-neutral-700"
classNames={{ classNames={{
// pb clears the fixed version bar (and the connected-host strip above it) so the // pb clears the fixed version bar (and the connected-host strip above it) so the
// last tabs stay reachable once the list scrolls. // last tabs stay reachable once the list scrolls. pt-6 clears macOS's
tabList: 'w-full gap-3 pb-10' + (platform() === 'macos' ? ' pt-6' : ''), tabList:
'w-full gap-3 pb-10' +
(platform() === 'macos' && !isPreview ? ' pt-6' : ''),
tab: 'h-14 justify-start rounded-large', tab: 'h-14 justify-start rounded-large',
tabContent: 'pl-8', tabContent: 'pl-8',
}} }}
@@ -316,19 +320,21 @@ export default function Settings() {
> >
<ProxySection /> <ProxySection />
</Tab> </Tab>
<Tab {!isPreview && (
key="license" <Tab
title={ key="license"
<div className="flex items-center gap-2"> title={
<MedalIcon className="w-5 h-5" /> <div className="flex items-center gap-2">
<span>License</span> <MedalIcon className="w-5 h-5" />
</div> <span>License</span>
} </div>
data-focus-visible="false" }
className="w-full max-h-screen p-0 overflow-scroll overscroll-none" data-focus-visible="false"
> className="w-full max-h-screen p-0 overflow-scroll overscroll-none"
<LicenseSection /> >
</Tab> <LicenseSection />
</Tab>
)}
<Tab <Tab
key="about" key="about"
title={ title={
@@ -352,10 +358,15 @@ export default function Settings() {
)} )}
<div className="absolute bottom-0 left-0 flex flex-col h-12 gap-4 p-4 border-t border-r w-52 bg-content3 dark:bg-content1 border-divider dark:border-neutral-700"> <div className="absolute bottom-0 left-0 flex flex-col h-12 gap-4 p-4 border-t border-r w-52 bg-content3 dark:bg-content1 border-divider dark:border-neutral-700">
<p <p
className="text-[10px] text-center text-neutral-500 hover:text-neutral-400 cursor-pointer" className={cn(
'text-[10px] text-center cursor-pointer',
isPreview
? 'text-white font-semibold'
: 'text-neutral-500 hover:text-neutral-400 '
)}
onClick={() => openUrl('https://github.com/rclone-ui/rclone-ui')} onClick={() => openUrl('https://github.com/rclone-ui/rclone-ui')}
> >
UI v{uiVersion}, CLI v{cliVersion} {isPreview ? 'rcloneui.com' : `UI v${uiVersion}, CLI v${cliVersion}`}
</p> </p>
</div> </div>
</div> </div>
+4 -1
View File
@@ -5,6 +5,7 @@ import { message } from '@tauri-apps/plugin-dialog'
import { ChevronRightIcon, RefreshCcwIcon, SearchCheckIcon } from 'lucide-react' import { ChevronRightIcon, RefreshCcwIcon, SearchCheckIcon } from 'lucide-react'
import { startTransition, useCallback, useMemo, useState } from 'react' import { startTransition, useCallback, useMemo, useState } from 'react'
import { buildReadablePathMultiple, formatBytes } from '../../lib/format' import { buildReadablePathMultiple, formatBytes } from '../../lib/format'
import { useIsPreview } from '../../lib/preview'
import { listTransfers } from '../../lib/rclone/api' import { listTransfers } from '../../lib/rclone/api'
import { usePersistedStore } from '../../store/persisted' import { usePersistedStore } from '../../store/persisted'
import type { JobItem } from '../../types/jobs' import type { JobItem } from '../../types/jobs'
@@ -121,6 +122,7 @@ export default function Transfers() {
} }
function JobCard({ job, onSelect }: { job: JobItem; onSelect: (job: JobItem) => void }) { function JobCard({ job, onSelect }: { job: JobItem; onSelect: (job: JobItem) => void }) {
const isPreview = useIsPreview()
return ( return (
<Card <Card
key={job.id} key={job.id}
@@ -191,7 +193,8 @@ function JobCard({ job, onSelect }: { job: JobItem; onSelect: (job: JobItem) =>
> >
<Progress <Progress
value={job.progress} value={job.progress}
isStriped={true} disableAnimation={isPreview}
isStriped={!(job.isChecking && job.totalBytes === 0)}
isIndeterminate={job.isChecking && job.totalBytes === 0} isIndeterminate={job.isChecking && job.totalBytes === 0}
/> />
</Tooltip> </Tooltip>
+1
View File
@@ -6,6 +6,7 @@ export default {
'./index.html', './index.html',
'./src/**/*.{js,ts,jsx,tsx}', './src/**/*.{js,ts,jsx,tsx}',
'./lib/**/*.{js,ts,jsx,tsx}', './lib/**/*.{js,ts,jsx,tsx}',
'./video/**/*.{js,ts,jsx,tsx}',
'./node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}', './node_modules/@heroui/theme/dist/**/*.{js,ts,jsx,tsx}',
], ],
theme: { theme: {