commit
17ddaa3427
29 changed files with 148 additions and 118 deletions
|
|
@ -103,6 +103,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[ignore]
|
||||
async fn read_metainfo_from_dht() {
|
||||
init_logging();
|
||||
|
||||
|
|
|
|||
2
crates/librqbit/webui/dist/assets/index.css
vendored
2
crates/librqbit/webui/dist/assets/index.css
vendored
File diff suppressed because one or more lines are too long
18
crates/librqbit/webui/dist/assets/index.js
vendored
18
crates/librqbit/webui/dist/assets/index.js
vendored
File diff suppressed because one or more lines are too long
6
crates/librqbit/webui/dist/manifest.json
vendored
6
crates/librqbit/webui/dist/manifest.json
vendored
|
|
@ -4,14 +4,14 @@
|
|||
"src": "assets/logo.svg"
|
||||
},
|
||||
"index.css": {
|
||||
"file": "assets/index-458d2033.css",
|
||||
"file": "assets/index-8d563632.css",
|
||||
"src": "index.css"
|
||||
},
|
||||
"index.html": {
|
||||
"css": [
|
||||
"assets/index-458d2033.css"
|
||||
"assets/index-8d563632.css"
|
||||
],
|
||||
"file": "assets/index-1daa8daf.js",
|
||||
"file": "assets/index-c39122a8.js",
|
||||
"isEntry": true,
|
||||
"src": "index.html"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ const AlertDanger: React.FC<{
|
|||
onClose?: () => void;
|
||||
}> = ({ title, children, onClose }) => {
|
||||
return (
|
||||
<div className="bg-red-200 p-3 rounded-md mb-3">
|
||||
<div className="bg-red-200 p-3 rounded-md mb-3 dark:bg-red-800/60">
|
||||
<div className="flex justify-between mb-2">
|
||||
<h2 className="text-lg font-semibold">{title}</h2>
|
||||
{onClose && (
|
||||
|
|
|
|||
|
|
@ -7,19 +7,19 @@ import Logo from "../../assets/logo.svg?react";
|
|||
export const Header = ({ title }: { title: string }) => {
|
||||
const [name, version] = title.split("-");
|
||||
return (
|
||||
<header className="bg-slate-50 drop-shadow-lg flex flex-wrap justify-center lg:justify-between items-center mb-3">
|
||||
<header className="bg-slate-50 drop-shadow-lg flex flex-wrap justify-center lg:justify-between items-center dark:bg-slate-800 mb-3">
|
||||
<div className="flex flex-nowrap items-center justify-between m-2">
|
||||
<Logo className="w-10 h-10 p-1" alt="logo" />
|
||||
<h1 className="flex items-center">
|
||||
<h1 className="flex items-center dark:text-white">
|
||||
<div className="text-3xl">{name}</div>
|
||||
<div className="bg-blue-100 text-blue-800 text-xl font-semibold me-2 px-2.5 py-0.5 rounded ms-2">
|
||||
<div className="bg-blue-100 text-blue-800 text-xl font-semibold me-2 px-2.5 py-0.5 rounded ms-2 dark:bg-blue-900 dark:text-white">
|
||||
{version}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-1 m-2">
|
||||
<MagnetInput className="flex-grow justify-center" />
|
||||
<FileInput className="flex-grow justify-center" />
|
||||
<MagnetInput className="flex-grow justify-center dark:text-white" />
|
||||
<FileInput className="flex-grow justify-center dark:text-white" />
|
||||
</div>
|
||||
</header>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -31,13 +31,16 @@ const LogSpan: React.FC<{ span: Span }> = ({ span }) => (
|
|||
<>
|
||||
<span className="font-bold">{span.name}</span>
|
||||
<SpanFields span={span} />
|
||||
<span className="font-bold">:</span>
|
||||
</>
|
||||
);
|
||||
|
||||
const Fields: React.FC<{ fields: JSONLogLine["fields"] }> = ({ fields }) => (
|
||||
<span
|
||||
className={`m-1 ${
|
||||
fields.message.match(/error|fail/g) ? "text-red-500" : "text-slate-500"
|
||||
fields.message.match(/error|fail/g)
|
||||
? "text-red-500"
|
||||
: "text-slate-500 dark:text-slate-200"
|
||||
}`}
|
||||
>
|
||||
{fields.message}
|
||||
|
|
@ -72,7 +75,9 @@ export const LogLine: React.FC<{ line: JSONLogLine }> = React.memo(
|
|||
|
||||
return (
|
||||
<p className="font-mono m-0 text-break text-[10px]">
|
||||
<span className="m-1 text-slate-500">{parsed.timestamp}</span>
|
||||
<span className="m-1 text-slate-500 dark:text-slate-400">
|
||||
{parsed.timestamp}
|
||||
</span>
|
||||
<span className={`m-1 ${classNameByLevel(parsed.level)}`}>
|
||||
{parsed.level}
|
||||
</span>
|
||||
|
|
@ -80,7 +85,9 @@ export const LogLine: React.FC<{ line: JSONLogLine }> = React.memo(
|
|||
<span className="m-1">
|
||||
{parsed.spans?.map((span, i) => <LogSpan key={i} span={span} />)}
|
||||
</span>
|
||||
<span className="m-1 text-slate-500">{parsed.target}</span>
|
||||
<span className="m-1 text-slate-500 dark:text-slate-400">
|
||||
{parsed.target}
|
||||
</span>
|
||||
<Fields fields={parsed.fields} />
|
||||
</p>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export const ProgressBar = ({ now, variant, label }: Props) => {
|
|||
}[variant ?? "info"];
|
||||
|
||||
return (
|
||||
<div className={"w-full bg-gray-200 rounded-full"}>
|
||||
<div className={"w-full bg-gray-200 rounded-full dark:bg-gray-500"}>
|
||||
<div
|
||||
className={`text-xs bg-blue-500 font-medium transition-all text-center p-0.5 leading-none rounded-full ${variantClassName}`}
|
||||
style={{ width: `${now}%` }}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
export const Spinner = () => {
|
||||
export const Spinner = ({ label }: { label?: string }) => {
|
||||
return (
|
||||
<div role="status">
|
||||
<div className="flex gap-2 items-center w-full justify-center">
|
||||
<svg
|
||||
aria-hidden="true"
|
||||
className="inline w-8 h-8 text-gray-200 animate-spin fill-blue-600"
|
||||
className="w-8 h-8 text-gray-200 animate-spin dark:text-gray-600 fill-blue-600"
|
||||
viewBox="0 0 100 101"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
|
|
@ -17,7 +17,11 @@ export const Spinner = () => {
|
|||
fill="currentFill"
|
||||
/>
|
||||
</svg>
|
||||
<span className="sr-only">Loading...</span>
|
||||
{label ? (
|
||||
<span className="text-sm">{label} ...</span>
|
||||
) : (
|
||||
<span className="sr-only">Loading...</span>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import {
|
||||
MdCheck,
|
||||
MdCheckCircle,
|
||||
MdDownload,
|
||||
MdError,
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ export const TorrentRow: React.FC<{
|
|||
};
|
||||
|
||||
return (
|
||||
<section className="flex flex-col sm:flex-row items-center gap-2 border p-2 border-gray-200 rounded-xl shadow-xs hover:drop-shadow-sm">
|
||||
<section className="flex flex-col sm:flex-row items-center gap-2 border p-2 border-gray-200 rounded-xl shadow-xs hover:drop-shadow-sm dark:bg-slate-800 dark:border-slate-900">
|
||||
{/* Icon */}
|
||||
<div className="hidden md:block">{statusIcon("w-10 h-10")}</div>
|
||||
{/* Name, progress, stats */}
|
||||
|
|
@ -53,7 +53,7 @@ export const TorrentRow: React.FC<{
|
|||
{detailsResponse && (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="md:hidden">{statusIcon("w-5 h-5")}</div>
|
||||
<div className="text-left text-lg text-gray-900 text-ellipsis break-all">
|
||||
<div className="text-left text-lg text-gray-900 text-ellipsis break-all dark:text-slate-200">
|
||||
{getLargestFileName(detailsResponse)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,26 +6,21 @@ export const TorrentsList = (props: {
|
|||
torrents: Array<TorrentId> | null;
|
||||
loading: boolean;
|
||||
}) => {
|
||||
if (props.torrents === null && props.loading) {
|
||||
return <Spinner />;
|
||||
}
|
||||
// The app either just started, or there was an error loading torrents.
|
||||
if (props.torrents === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (props.torrents.length === 0) {
|
||||
return (
|
||||
<div className="text-center">
|
||||
<p>No existing torrents found.</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className="flex flex-col gap-2 mx-2">
|
||||
{props.torrents.map((t: TorrentId) => (
|
||||
<Torrent id={t.id} key={t.id} torrent={t} />
|
||||
))}
|
||||
<div className="flex flex-col gap-2 mx-2 pb-3 sm:px-7">
|
||||
{props.torrents === null ? (
|
||||
props.loading ? (
|
||||
<Spinner label="Loading torrent list" />
|
||||
) : null
|
||||
) : props.torrents.length === 0 ? (
|
||||
<p className="text-center">No existing torrents found.</p>
|
||||
) : (
|
||||
props.torrents.map((t: TorrentId) => (
|
||||
<>
|
||||
<Torrent id={t.id} key={t.id} torrent={t} />
|
||||
</>
|
||||
))
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,11 +8,14 @@ export const Button: React.FC<{
|
|||
children: ReactNode;
|
||||
}> = ({ onClick, children, className, disabled, variant }) => {
|
||||
let variantClassNames = {
|
||||
secondary: "hover:bg-blue-500 transition-colors hover:text-white",
|
||||
secondary:
|
||||
"hover:bg-blue-500 transition-colors hover:text-white dark:hover:bg-blue-900/50",
|
||||
danger:
|
||||
"bg-red-400 text-white border-green-50 hover:border-red-700 hover:bg-red-600",
|
||||
primary: "bg-blue-600 text-white hover:bg-blue-800 disabled:bg-blue-200",
|
||||
cancel: "hover:bg-slate-200",
|
||||
"bg-red-400 text-white border-green-50 hover:border-red-700 hover:bg-red-600 dark:bg-red-800 dark:border-none dark:hover:bg-red-900",
|
||||
primary:
|
||||
"bg-blue-600 text-white hover:bg-blue-800 disabled:bg-blue-200 dark:disabled:bg-slate-600 dark:disabled:text-slate-300 dark:border-none",
|
||||
cancel:
|
||||
"hover:bg-slate-200 dark:bg-slate-600 dark:hover:bg-slate-700 dark:border-none",
|
||||
none: "",
|
||||
}[variant ?? "secondary"];
|
||||
return (
|
||||
|
|
@ -22,7 +25,7 @@ export const Button: React.FC<{
|
|||
e.preventDefault();
|
||||
onClick();
|
||||
}}
|
||||
className={`flex inline-flex items-center gap-1 border rounded-lg border disabled:cursor-not-allowed px-2 py-1 transition-colors duration-300 ${variantClassNames} ${className}`}
|
||||
className={`inline-flex items-center gap-1 border rounded-lg disabled:cursor-not-allowed px-2 py-1 transition-colors duration-300 dark:border-slate-700 ${variantClassNames} ${className}`}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ export const FileInput = ({ className }: { className?: string }) => {
|
|||
resetData={reset}
|
||||
className={className}
|
||||
>
|
||||
<CgFileAdd color="blue" />
|
||||
<CgFileAdd className="text-blue-500 dark:text-white" />
|
||||
<div>Upload .torrent File</div>
|
||||
</UploadButton>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export const MagnetInput = ({ className }: { className?: string }) => {
|
|||
className={className}
|
||||
resetData={() => setMagnet(null)}
|
||||
>
|
||||
<CgLink color="blue" />
|
||||
<CgLink className="text-blue-500 dark:text-white" />
|
||||
<div>Add Torrent from Magnet / URL</div>
|
||||
</UploadButton>
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ export const TorrentActions: React.FC<{
|
|||
};
|
||||
|
||||
return (
|
||||
<div className="flex w-full justify-center gap-2">
|
||||
<div className="flex w-full justify-center gap-2 dark:text-slate-300">
|
||||
{canUnpause && (
|
||||
<IconButton onClick={unpause} disabled={disabled}>
|
||||
<FaPlay className="hover:text-green-500 transition-colors duration-300" />
|
||||
|
|
|
|||
|
|
@ -24,7 +24,11 @@ export const FormCheckbox: React.FC<{
|
|||
</div>
|
||||
<div className="text-sm flex flex-col gap-1">
|
||||
<label htmlFor={name}>{label}</label>
|
||||
{help && <div className="text-xs text-slate-500 mb-3">{help}</div>}
|
||||
{help && (
|
||||
<div className="text-xs text-slate-500 dark:text-slate-300 mb-3">
|
||||
{help}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -25,11 +25,13 @@ export const FormInput: React.FC<{
|
|||
}) => {
|
||||
return (
|
||||
<div className="flex flex-col gap-2 text-sm mb-2">
|
||||
<label htmlFor={name}>{label}</label>
|
||||
<label htmlFor={name} className="dark:text-white">
|
||||
{label}
|
||||
</label>
|
||||
<input
|
||||
autoFocus={autoFocus}
|
||||
type={inputType}
|
||||
className="block border rounded bg-transparent py-1.5 pl-2 text-gray-800 focus:ring-0 sm:text-sm sm:leading-6"
|
||||
className="block border rounded bg-transparent py-1.5 pl-2 text-gray-800 focus:ring-0 sm:text-sm sm:leading-6 dark:text-slate-300"
|
||||
id={name}
|
||||
name={name}
|
||||
disabled={disabled}
|
||||
|
|
@ -38,7 +40,9 @@ export const FormInput: React.FC<{
|
|||
onKeyDown={onKeyDown}
|
||||
onChange={onChange}
|
||||
/>
|
||||
{help && <div className="text-xs text-slate-500">{help}</div>}
|
||||
{help && (
|
||||
<div className="text-xs text-slate-500 dark:text-slate-300">{help}</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ export const DeleteTorrentModal: React.FC<{
|
|||
return (
|
||||
<Modal isOpen={show} onClose={onHide} title="Delete torrent">
|
||||
<ModalBody>
|
||||
<p className="text-gray-700">
|
||||
<p className="text-gray-700 dark:text-slate-300">
|
||||
Are you sure you want to delete the torrent?
|
||||
</p>
|
||||
|
||||
|
|
@ -65,7 +65,10 @@ export const DeleteTorrentModal: React.FC<{
|
|||
checked={deleteFiles}
|
||||
placeholder="Also delete files"
|
||||
/>
|
||||
<label htmlFor="deleteFiles" className="ml-2 text-gray-700">
|
||||
<label
|
||||
htmlFor="deleteFiles"
|
||||
className="ml-2 text-gray-700 dark:text-slate-300"
|
||||
>
|
||||
Also delete files
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -101,7 +101,7 @@ export const FileSelectionModal = (props: {
|
|||
|
||||
const getBody = () => {
|
||||
if (listTorrentLoading) {
|
||||
return <Spinner />;
|
||||
return <Spinner label="Loading torrent contents" />;
|
||||
} else if (listTorrentError) {
|
||||
return <ErrorComponent error={listTorrentError}></ErrorComponent>;
|
||||
} else if (listTorrentResponse) {
|
||||
|
|
|
|||
|
|
@ -16,8 +16,8 @@ const ModalHeader: React.FC<{
|
|||
title: string;
|
||||
}> = ({ onClose, title }) => {
|
||||
return (
|
||||
<div className="flex p-3 justify-between items-center border-b">
|
||||
<h2 className="text-xl font-semibold">{title}</h2>
|
||||
<div className="flex p-3 justify-between items-center border-b dark:border-slate-600">
|
||||
<h2 className="text-xl font-semibold dark:slate-300">{title}</h2>
|
||||
{onClose && (
|
||||
<button
|
||||
className="text-gray-500 hover:text-gray-700"
|
||||
|
|
@ -39,17 +39,19 @@ export const Modal: React.FC<ModalProps> = ({
|
|||
className,
|
||||
}) => {
|
||||
const renderBackdrop = () => {
|
||||
return <div className="fixed inset-0 bg-black/30 z-[300]"></div>;
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/30 z-[300] dark:bg-black/60 backdrop-blur"></div>
|
||||
);
|
||||
};
|
||||
return (
|
||||
<RestartModal
|
||||
show={isOpen}
|
||||
onHide={onClose}
|
||||
renderBackdrop={renderBackdrop}
|
||||
className={`fixed z-[301] top-0 left-0 w-full h-full block overflow-x-hidden overflow-y-auto`}
|
||||
className="fixed z-[301] top-0 left-0 w-full h-full block overflow-x-hidden overflow-y-auto"
|
||||
>
|
||||
<div
|
||||
className={`bg-white shadow-lg my-8 mx-auto max-w-2xl rounded ${className}`}
|
||||
className={`bg-white shadow-lg my-8 mx-auto max-w-2xl rounded ${className} dark:bg-slate-800 dark:text-zinc-50`}
|
||||
>
|
||||
<ModalHeader onClose={onClose} title={title} />
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { ReactNode } from "react";
|
||||
|
||||
export const ModalBody = ({ children }: { children: ReactNode }) => {
|
||||
return <div className="p-3 border-b">{children}</div>;
|
||||
return <div className="p-3 border-b dark:border-slate-500">{children}</div>;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
@tailwind utilities;
|
||||
|
|
|
|||
21
crates/librqbit/webui/src/helper/darkMode.ts
Normal file
21
crates/librqbit/webui/src/helper/darkMode.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
let darkMode = window.matchMedia("(prefers-color-scheme: dark)").matches;
|
||||
|
||||
window
|
||||
.matchMedia("(prefers-color-scheme: dark)")
|
||||
.addEventListener("change", (event) => {
|
||||
DarkMode.setDark(event.matches);
|
||||
});
|
||||
|
||||
export const DarkMode = {
|
||||
isDark: () => darkMode,
|
||||
setDark: (value: boolean) => {
|
||||
darkMode = value;
|
||||
document.body.classList.toggle("dark", darkMode);
|
||||
return darkMode;
|
||||
},
|
||||
toggle: () => {
|
||||
DarkMode.setDark(!darkMode);
|
||||
},
|
||||
};
|
||||
|
||||
DarkMode.setDark(darkMode);
|
||||
|
|
@ -4,9 +4,10 @@ import { AppContext, APIContext } from "./context";
|
|||
import { RootContent } from "./components/RootContent";
|
||||
import { customSetInterval } from "./helper/customSetInterval";
|
||||
import { IconButton } from "./components/buttons/IconButton";
|
||||
import { BsBodyText } from "react-icons/bs";
|
||||
import { BsBodyText, BsMoon } from "react-icons/bs";
|
||||
import { LogStreamModal } from "./components/modal/LogStreamModal";
|
||||
import { Header } from "./components/Header";
|
||||
import { DarkMode } from "./helper/darkMode";
|
||||
|
||||
export interface ErrorWithLabel {
|
||||
text: string;
|
||||
|
|
@ -66,26 +67,34 @@ export const RqbitWebUI = (props: {
|
|||
|
||||
return (
|
||||
<AppContext.Provider value={context}>
|
||||
<Header title={props.title} />
|
||||
<div className="relative">
|
||||
{/* Menu buttons */}
|
||||
<div className="absolute top-0 start-0 pl-2 z-10">
|
||||
{props.menuButtons &&
|
||||
props.menuButtons.map((b, i) => <span key={i}>{b}</span>)}
|
||||
<IconButton onClick={() => setLogsOpened(true)}>
|
||||
<BsBodyText />
|
||||
</IconButton>
|
||||
<div className="dark:bg-gray-900 dark:text-zinc-50 min-h-screen">
|
||||
<Header title={props.title} />
|
||||
<div className="relative">
|
||||
{/* Menu buttons */}
|
||||
<div className="absolute top-0 start-0 pl-2 z-10">
|
||||
{props.menuButtons &&
|
||||
props.menuButtons.map((b, i) => <span key={i}>{b}</span>)}
|
||||
<IconButton onClick={() => setLogsOpened(true)}>
|
||||
<BsBodyText />
|
||||
</IconButton>
|
||||
<IconButton onClick={DarkMode.toggle}>
|
||||
<BsMoon />
|
||||
</IconButton>
|
||||
</div>
|
||||
|
||||
<RootContent
|
||||
closeableError={closeableError}
|
||||
otherError={otherError}
|
||||
torrents={torrents}
|
||||
torrentsLoading={torrentsLoading}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<RootContent
|
||||
closeableError={closeableError}
|
||||
otherError={otherError}
|
||||
torrents={torrents}
|
||||
torrentsLoading={torrentsLoading}
|
||||
<LogStreamModal
|
||||
show={logsOpened}
|
||||
onClose={() => setLogsOpened(false)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<LogStreamModal show={logsOpened} onClose={() => setLogsOpened(false)} />
|
||||
</AppContext.Provider>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,25 +1,5 @@
|
|||
/** @type {import('tailwindcss').Config} */
|
||||
export default {
|
||||
content: [
|
||||
"./index.html",
|
||||
"./src/**/*.{js,ts,jsx,tsx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {
|
||||
fadeIn: {
|
||||
from: { opacity: 0 },
|
||||
to: { opacity: 1 },
|
||||
},
|
||||
fadeOut: {
|
||||
from: { opacity: 1 },
|
||||
to: { opacity: 0 },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
'fade-in': 'fadeIn 0.3s ease-in-out',
|
||||
'fade-out': 'fadeOut 0.3s ease-in-out',
|
||||
},
|
||||
},
|
||||
plugins: [],
|
||||
}
|
||||
|
||||
content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
|
||||
darkMode: "class",
|
||||
};
|
||||
|
|
|
|||
4
desktop/src-tauri/Cargo.lock
generated
4
desktop/src-tauri/Cargo.lock
generated
|
|
@ -1867,7 +1867,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "librqbit"
|
||||
version = "5.1.0"
|
||||
version = "5.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
|
|
@ -3012,7 +3012,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "rqbit-desktop"
|
||||
version = "5.1.0"
|
||||
version = "5.2.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64 0.21.5",
|
||||
|
|
|
|||
|
|
@ -184,7 +184,8 @@ export const ConfigModal: React.FC<{
|
|||
const isActive = t === tab;
|
||||
let classNames = "text-slate-300";
|
||||
if (isActive) {
|
||||
classNames = "text-slate-800 border-b-2 border-blue-800";
|
||||
classNames =
|
||||
"text-slate-800 border-b-2 border-blue-800 dark:border-blue-200 dark:text-white";
|
||||
}
|
||||
return (
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -4,8 +4,5 @@ export default {
|
|||
"./src/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
"../crates/librqbit/webui/src/**/*.{js,ts,jsx,tsx,mdx}",
|
||||
],
|
||||
theme: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [],
|
||||
darkMode: "class",
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue